# httptest [![](https://meritbadge.herokuapp.com/httptest)](https://crates.io/crates/httptest) [![]( https://docs.rs/httptest/badge.svg)](https://docs.rs/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 ```rust #[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::>(); // 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 to allow using the body // response matcher. let body = resp.collect().await.unwrap().to_bytes(); assert_eq!( json!({"result": "success"}), serde_json::from_slice::(&body).unwrap() ); // on Drop the server will assert all expectations have been met and will // panic if not. } ```