Skip to content

ggriffiniii/httptest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

7143f1b · Feb 8, 2025
Oct 30, 2020
Feb 8, 2025
Feb 8, 2025
Dec 7, 2019
Feb 8, 2025
Dec 13, 2019
Dec 13, 2019
Apr 5, 2024

Repository files navigation

httptest

Provide convenient mechanism for testing http clients against a locally running http server. The typical usage is as follows:

  • Start a server
  • Configure the server by adding expectations
  • Test your http client by making requests to the server
  • On Drop the server verifies all expectations were met.

Example Test

#[tokio::test]
async fn test_readme() {
    use http_body_util::{BodyExt, Full};
    use httptest::{matchers::*, responders::*, Expectation, Server};
    use hyper_util::client::legacy::Client;
    use serde_json::json;
    // Starting a logger within the test can make debugging a failed test
    // easier. The mock http server will log::debug every request and response
    // received along with what, if any, matcher was found for the request. When
    // env_logger is initialized running the test with `RUST_LOG=httptest=debug
    // cargo test` can provide that information on stderr.
    let _ = pretty_env_logger::try_init();
    // Start a server running on a local ephemeral port.
    let server = Server::run();
    // Configure the server to expect a single GET /foo request and respond
    // with a 200 status code.
    server.expect(
        Expectation::matching(request::method_path("GET", "/foo")).respond_with(status_code(200)),
    );
    // Configure the server to also receive between 1 and 3 POST /bar requests
    // with a json body matching {'foo': 'bar'}, and respond with a json body
    // {'result': 'success'}
    server.expect(
        Expectation::matching(all_of![
            request::method("POST"),
            request::path("/bar"),
            request::body(json_decoded(eq(json!({"foo": "bar"})))),
        ])
        .times(1..=3)
        .respond_with(json_encoded(json!({"result": "success"}))),
    );

    // The server provides server.addr() that returns the address of the
    // locally running server, or more conveniently provides a server.url()
    // method that gives a fully formed http url to the provided path.
    let url = server.url("/foo");

    // Now test your http client against the server.
    let client = Client::builder(hyper_util::rt::TokioExecutor::new())
        .build_http::<Full<hyper::body::Bytes>>();

    // Issue the GET /foo to the server.
    let resp = client.get(url).await.unwrap();
    // Optionally use response matchers to assert the server responded as
    // expected.

    // Assert the response was a 200.
    assert_eq!(200, resp.status().as_u16());

    // Issue a POST /bar with {'foo': 'bar'} json body.
    let post_req = http::Request::post(server.url("/bar"))
        .body(json!({"foo": "bar"}).to_string().into())
        .unwrap();
    let resp = client.request(post_req).await.unwrap();

    // Assert the response was a 200 with a json body of {'result': 'success'}
    assert_eq!(200, resp.status().as_u16());

    // Read the entire response body into a Vec<u8> to allow using the body
    // response matcher.
    let body = resp.collect().await.unwrap().to_bytes();
    assert_eq!(
        json!({"result": "success"}),
        serde_json::from_slice::<serde_json::Value>(&body).unwrap()
    );

    // on Drop the server will assert all expectations have been met and will
    // panic if not.
}

About

No description, website, or topics provided.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published

Languages