Expand description
Allows fluent assertions for various http client responses. Supports actix-web, rocket, reqwest, hyper, awc (Actix Web Client), surf and isahc.
It works for blocking or async client methods and for responses wrapped in Result
.
§API
Here’s the list of all the provided asserters.
use asserhttp::*;
#[test]
fn my_test() {
// status
.expect_status(200)
.expect_status(Status::Ok)
.expect_status_in_range(200, 400)
.expect_status_success()
.expect_status_redirection()
.expect_status_client_error()
.expect_status_server_error()
.expect_status_ok()
.expect_status_created()
.expect_status_accepted()
.expect_status_no_content()
.expect_status_partial_content()
.expect_status_bad_request()
.expect_status_unauthorized()
.expect_status_forbidden()
.expect_status_not_found()
.expect_status_conflict()
.expect_status_gone()
.expect_status_internal_server_error()
// header
.expect_header("content-type", "application/pdf")
.expect_header(headers::CONTENT_TYPE, "application/pdf")
.expect_header("content-type", |h| assert_eq!(h, "application/pdf"))
.expect_headers("cache-control", ["no-cache", "no-store"])
.expect_headers(headers::CACHE_CONTROL, ["no-cache", "no-store"])
.expect_headers("cache-control", |h: Vec<&str>| assert!(h.contains(&"a") && h.contains(&"b")))
.expect_header_present("x-my-header")
.expect_header_present(headers::CONTENT_TYPE)
.expect_header_absent("x-my-header")
.expect_header_absent(headers::ACCEPT)
.expect_content_type_json()
.expect_content_type_text()
// body
.expect_body_json(|b: Value| assert_eq!(b, json!({"a": "b"})))
.expect_body_json_eq(json!({"name": "jdoe"}))
.expect_body_text(|b| assert_eq!(b, "abcd"))
.expect_body_text_eq("abcd")
.expect_body_text_matches("[a-z]+")
.expect_body_bytes(|b| assert_eq!(b, b"abcd"))
.expect_body_bytes_eq(b"abcd")
.expect_body_present()
.expect_body_absent();
}
§Example
§actix-web
Use actix
feature.
For unit testing
use actix_web::{HttpRequest, HttpResponse, test::TestRequest};
use serde_json::json;
use asserhttp::*;
#[actix_web::test]
async fn sample_test() {
async fn handler(_: HttpRequest) -> HttpResponse { HttpResponse::Ok().body(json!({"a": "b"})) }
handler(TestRequest::get().to_http_request()).await
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"a": "b"}));
// and many more !
}
For integration tests
use actix_web::{App, HttpResponse, test::{call_service, init_service, TestRequest}, web};
use serde_json::json;
use asserhttp::*;
#[actix_web::test]
async fn sample_test() {
let app = App::new().route("/", web::get().to(|| async { HttpResponse::Ok().body(json!({"a": "b"})) }));
call_service(&mut init_service(app).await, TestRequest::get().to_request()).await
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"a": "b"}));
// and many more !
}
§rocket
Use rocket
feature.
use rocket::{get, http::Status, local::asynchronous::Client, routes};
use serde_json::{json, Value};
use asserhttp::*;
#[rocket::async_test]
async fn sample_test() {
#[get("/")]
fn endpoint() -> Value { json!({"a": "b"}) }
let client = Client::tracked(rocket::build().mount("/", routes![endpoint])).await.unwrap();
client.get("/").dispatch().await
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"a": "b"}));
}
§reqwest
Use reqwest
feature.
use reqwest;
use asserhttp::*;
use serde_json::json;
#[tokio::test]
async fn sample_test() {
reqwest::get("http://localhost/api/any").await.unwrap().expect_status_ok();
// no need to call `.unwrap()` directly
reqwest::get("http://localhost/api/any").await.expect_status(200);
reqwest::get("http://localhost/api/any").await.expect_status_ok();
reqwest::get("http://localhost/api/any").await.expect_status_bad_request();
reqwest::get("http://localhost/api/any").await.expect_status_internal_server_error();
// chain expectations
reqwest::get("http://localhost/api/any").await
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"name": "jdoe"}));
// and many more !
}
§hyper
Use hyper
feature.
use hyper::Client;
use asserhttp::*;
use serde_json::json;
#[tokio::test]
async fn sample_test() {
Client::new().get("http://localhost/api/any").await.unwrap().expect_status_ok();
// no need to call `.unwrap()` directly
Client::new().get("http://localhost/api/any").await.expect_status(200);
Client::new().get("http://localhost/api/any").await.expect_status_ok();
Client::new().get("http://localhost/api/any").await.expect_status_bad_request();
Client::new().get("http://localhost/api/any").await.expect_status_internal_server_error();
// chain expectations
Client::new().get("http://localhost/api/any").await
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"name": "jdoe"}));
// and many more !
}
§axum
Use axum
feature.
use asserhttp::*;
use serde_json::json;
use tower::ServiceExt as _;
#[tokio::test]
async fn sample_test() {
let app = axum::Router::new().route("/", axum::routing::get( || async move {
let mut axum_response = axum::response::Response::builder()
.status(axum::http::StatusCode::OK)
.body(json!({"a": "b"}).to_string())
.unwrap();
axum_response.headers_mut().insert("content-type", "application/json".parse().unwrap());
axum_response
}));
let req = axum::http::Request::builder().method(axum::http::Method::GET).uri("/").body(axum::body::Body::empty()).unwrap();
app.oneshot(req).await
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"name": "jdoe"}));
}
§awc (Actix Web Client)
Use actix-web-client
feature.
use awc::Client;
use asserhttp::*;
use serde_json::json;
#[actix_web::test]
async fn sample_test() {
Client::default().get("http://localhost/api/any").await.unwrap().expect_status_ok();
// no need to call `.unwrap()` directly
Client::default().get("http://localhost/api/any").await.expect_status(200);
Client::default().get("http://localhost/api/any").await.expect_status_ok();
Client::default().get("http://localhost/api/any").await.expect_status_bad_request();
Client::default().get("http://localhost/api/any").await.expect_status_internal_server_error();
// chain expectations
Client::default().get("http://localhost/api/any").await
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"name": "jdoe"}));
// and many more !
}
§surf
Use surf
feature.
use surf;
use asserhttp::*;
use serde_json::json;
#[tokio::test]
async fn sample_test() {
surf::get("http://localhost/api/any").await.unwrap().expect_status_ok();
// no need to call `.unwrap()` directly
surf::get("http://localhost/api/any").await.expect_status(200);
surf::get("http://localhost/api/any").await.expect_status_ok();
surf::get("http://localhost/api/any").await.expect_status_bad_request();
surf::get("http://localhost/api/any").await.expect_status_internal_server_error();
// chain expectations
surf::get("http://localhost/api/any").await
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"name": "jdoe"}));
// and many more !
}
§ureq
Use ureq
feature.
use ureq::OrAnyStatus;
use asserhttp::*;
use serde_json::json;
#[tokio::test]
async fn sample_test() {
ureq::get("http://localhost/api/any").call().or_any_status().unwrap().expect_status_ok();
// no need to call `.unwrap()` directly
ureq::get("http://localhost/api/any").call().or_any_status().expect_status(200);
ureq::get("http://localhost/api/any").call().or_any_status().expect_status_ok();
ureq::get("http://localhost/api/any").call().or_any_status().expect_status_bad_request();
ureq::get("http://localhost/api/any").call().or_any_status().expect_status_internal_server_error();
// chain expectations
ureq::get("http://localhost/api/any").call().or_any_status()
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"name": "jdoe"}));
// and many more !
}
§isahc
Use isahc
feature.
use isahc;
use asserhttp::*;
use serde_json::json;
#[tokio::test]
async fn sample_test() {
isahc::get_async("http://localhost/api/any").await.unwrap().expect_status_ok();
// no need to call `.unwrap()` directly
isahc::get_async("http://localhost/api/any").await.expect_status(200);
isahc::get_async("http://localhost/api/any").await.expect_status_ok();
isahc::get_async("http://localhost/api/any").await.expect_status_bad_request();
isahc::get_async("http://localhost/api/any").await.expect_status_internal_server_error();
// chain expectations
isahc::get_async("http://localhost/api/any").await
.expect_status_ok()
.expect_content_type_json()
.expect_body_json_eq(json!({"name": "jdoe"}));
// and many more !
}
§Errors
In case you would want to use asserhttp
in a non-test context (be aware though that it has not been written with performance in mind)
you likely do not want it to panic. In that case you can use the (non-default) fallible
feature which will bring in some try_*
variants
of the aforementioned methods, all of them yielding an AsserhttpError instead of panicking
use asserhttp::*;
#[tokio::test]
async fn my_test() {
assert!(matches!(AsserhttpError::StatusMismatch { actual: 200, expected: 201 }, isahc::get_async("http://localhost/api/any").await.try_expect_status(201)));
}
Modules§
- HTTP headers.
Macros§
Structs§
Enums§
- HTTP response status codes.
Traits§
- For assertions on http response
- For assertions on http response body
- For assertions on http response headers
- For assertions on http response status