alexliesenfeld / httpmock

HTTP mocking library for Rust.
MIT License
435 stars 40 forks source link

Question: Are mocked endpoints with same base url mapped to same resource/call? #80

Closed sbszcz closed 11 months ago

sbszcz commented 1 year ago

Hello,

first of all many thanks for that helpful crate. I use it a lot and it's usability and simplicity is awesome.

I came across a problem where I want to test an endpoint with pagination semantics. Here an example:

    let page_1_mock = server.mock(|when, then| {

        when.method("GET")          
            .path("/content");
        then.status(200)
            .header("content-type", "application/json; charset=utf-8")
            .header("NextLink", "http://127.0.0.1:12345/content?page=2")
            .body(json!(
                [
                  {
                      "content": "example1",
                  }
                ]
            ).to_string());
    });

    let page_2_mock = server.mock(|when, then| {

        when.method("GET")          
            .path("/content")
            .query_param("page", "2");
        then.status(200)
            .header("content-type", "application/json; charset=utf-8")
            .body(json!(
                [
                  {
                      "content": "example2",
                  }
                ]
            ).to_string());
    }); 

    let result = call_all_pages();

    assert_eq!(&result.len(), &2);

This test fails because the second call (extracted from the NextLink header of the first call result) seems to be executed against the page_1_mock again. Is this behaviour expected? I assumed that the calls to the mocks would be distinguished on their complete specification (url, header, query params, ...) but it seems that only the url (path) is the crucial feature.

Maybe I missed something?

Thanks.

alexliesenfeld commented 1 year ago

Thanks for reaching out!

yes, both requests would match the second mock. Some folks are working on a PR that may help you with this situation in the future.

In the meantime, you can structure your mock setup in such a way so that the first mock is defined second (page_2_mock first, page_1_mock second). Reason: If the httpmock server receives a request that matches more than one mock, the mocks are matched in descending order of definition and in that order the last (page_1_mock) wins.

Here is an example:

let server = MockServer::start();

let page_2_mock = server.mock(|when, then| {
    when.method("GET").path("/content").query_param("page", "2");
    then.status(200);
});

let page_1_mock = server.mock(|when, then| {
    when.method("GET").path("/content");
    then.status(200);
});

http_get(server.url("/content")).unwrap();
http_get(server.url("/content?page=2")).unwrap();

page_1_mock.assert_hits(1);
page_2_mock.assert_hits(1);
github-actions[bot] commented 11 months ago

This issue is stale because it has been open for 30 days with no activity.

github-actions[bot] commented 11 months ago

This issue was closed because it has been inactive for 14 days since being marked as stale.