Expand description
Django-shape test assertion helpers — assert_contains /
assert_redirects / assert_status / assert_messages on axum
Response objects. Issue #40.
Django-shape assertion helpers for axum response objects. Issue #40.
Quick assertions every Django test suite uses, ported to axum’s
Response shape so test code reads tighter:
ⓘ
use rustango::test_assertions::{assert_contains, assert_redirects, assert_status};
use tower::ServiceExt;
#[tokio::test]
async fn home_renders_greeting() {
let app = make_app();
let res = app.oneshot(Request::builder().uri("/").body(Body::empty()).unwrap()).await.unwrap();
assert_status(&res, 200);
assert_contains(res, "Hello, world!").await;
}
#[tokio::test]
async fn login_redirects_anonymous() {
let res = app.oneshot(req("/profile")).await.unwrap();
assert_redirects(&res, "/login?next=%2Fprofile");
}All helpers panic! on mismatch — cargo test reports them as
failures with descriptive messages. They don’t return Result so
tests stay readable (no ? clutter for assertions).
§Implemented
- [
assert_status] — exact-status match against a u16. - [
assert_status_in] — status is one of an allowed set. - [
assert_status_2xx] — status is in the 200–299 range. - [
assert_status_4xx] — status is in the 400–499 range. - [
assert_status_5xx] — status is in the 500–599 range. - [
assert_contains] — response body contains a UTF-8 substring. - [
assert_not_contains] — body does NOT contain a substring. - [
assert_contains_count] — body contains fragment N times (Django’sassertContains(..., count=N)). - [
assert_redirects] — 3xx status +Locationheader equality. - [
assert_header] — exact header value match. - [
assert_content_type] — sugar forassert_header("content-type", ...). - [
assert_json_eq] — body parses as JSON and equals expected (Django’sassertJSONEqual). - [
assert_json_not_eq] — body parses as JSON and DIFFERS from expected (Django’sassertJSONNotEqual). - [
assert_redirect_chain] — inspect the chain produced bycrate::test_client::TestClient::get_following_redirectsand assert it ends at a given (path, status). Django’sassertRedirects(..., fetch_redirect_response=True). - [
assert_messages] — read + assert on the flash-messages cookie fromcrate::messages. Gated ontemplate_viewsso consumers that use messages get the helper for free. - [
assert_cookie_set] — assert aSet-Cookieheader for the given cookie name was emitted, with optional exact-value match. - [
assert_cookie_not_set] — inverse: assert noSet-Cookiefor the given name was emitted.
§Out of scope (queued as follow-ups)
Django’s full assertion surface includes:
assertTemplateUsed— needs a Tera render-tracking hook; would require wrapping the Tera instance with an instrumented variant.assertNumQueries— needs a query-counting probe onPool. Doable with a wrapping executor but adds complexity.assertFormError(response, field, message)— needs Form errors in the rendered template context, which is template-shape specific. Right nowFormViewstampserrors: HashMapinto context — a helper could inspect that map but only for views that use the canonical key.
The helpers here are the high-leverage subset that needs nothing
beyond axum::Response plus the existing test_client redirect
follower.
Re-exports§
pub use query_counter::assert_num_queries;pub use query_counter::QueryCounter;
Modules§
- query_
counter - Django-shape
assertNumQueries— count SQL queries executed inside a scoped async block, then assert the count matches an expectation. Django-parity #431.
Functions§
- assert_
contains - Assert the response body contains
fragmentas a UTF-8 substring. Consumes the body, so the response is moved in. - assert_
contains_ count - Assert the response body contains
fragmentexactlycounttimes. Django’sassertContains(..., count=N).count = 0asserts absence — same asassert_not_contains. - assert_
content_ type - Assert the response
Content-Typeheader equalsexpected. Sugar forassert_headerwithname = "content-type". - assert_
cookie_ not_ set - Inverse of
assert_cookie_set— panic if aSet-CookiefornameIS present. Use to verify that a handler did NOT set a cookie under specific conditions (logged-out request shouldn’t touch the session cookie, etc.). - assert_
cookie_ set - Assert that the response emitted a
Set-Cookieheader for the given cookiename. Ifexpected_valueisSome, also assert the cookie’s value (the portion BEFORE the first;— i.e. thename=valuesegment withoutPath/HttpOnly/ etc.) equals that value byte-for-byte. Returns the matchedSet-Cookieheader value(s). - assert_
header - Assert that response header
nameequalsvalueexactly. Matches the header name case-insensitively (per RFC 7230), and the value byte-for-byte after UTF-8 decode. - assert_
json_ eq - Assert the response body, parsed as JSON, equals
expected. Django’sassertJSONEqual. Order-insensitive for object keys (JSON Value equality is structural). - assert_
json_ not_ eq - Inverse of
assert_json_eq— Django’sassertJSONNotEqual. Asserts the parsed JSON body differs fromunexpected. - assert_
messages - Drain the
Set-Cookievalue(s) for the messages framework cookie fromresand assert the staged messages matchexpected— list of(level_str, body)pairs. - assert_
not_ contains - Inverse of
assert_contains— panics when the fragment IS found. Useful for “the deleted post shouldn’t appear in the list” style assertions. - assert_
redirect_ chain - Assert the redirect chain produced by
crate::test_client::TestClient::get_following_redirectsends atfinal_pathwithfinal_status. Django’sassertRedirectswithfetch_redirect_response=True. - assert_
redirects - Assert the response is a 3xx redirect with
Locationexactly equal totarget. Catches both the status check and the URL check in one assertion — Django’sassertRedirectsshape. - assert_
status - Assert the response status equals
expected. Panics on mismatch with the actual status in the message. - assert_
status_ 2xx - Assert the response status is in the 2xx range (success). Sugar for the very common “any success” check.
- assert_
status_ 4xx - Assert the response status is in the 4xx range (client error).
- assert_
status_ 5xx - Assert the response status is in the 5xx range (server error). Useful for negative tests of error pages / handlers that must surface internal failures rather than degrade silently.
- assert_
status_ in - Assert the response status is one of
allowed. Useful when a handler can legitimately return either of several success codes — e.g.POST /itemsmight return 200 (idempotent touch) OR 201 (new resource).