Testing with TestClient
Drive the full pipeline in-process without binding a socket.
Basic usage
Build an App with .build() instead of .start(), then wrap it:
use churust::prelude::*; use churust::TestClient; #[churust::main] async fn main() { let app = Churust::server() .routing(|r| { r.get("/ping", |_c: Call| async { "pong" }); }) .build(); let res = TestClient::new(app).get("/ping").send().await; assert_eq!(res.status(), StatusCode::OK); assert_eq!(res.text(), "pong"); }
In real tests, use your test harness’s async runtime (for example
#[tokio::test] or Churust’s main only in binaries).
Requests
#![allow(unused)] fn main() { let client = TestClient::new(app); let res = client .post("/notes") .header("authorization", "Bearer admin-token") .header("content-type", "application/json") .body(r#"{"text":"hi"}"#) .send() .await; assert_eq!(res.status(), StatusCode::CREATED); }
Helpers include get, post, put, delete, and a generic request(method, uri).
Assertions
#![allow(unused)] fn main() { res.status() res.headers() res.header("content-type") res.body_bytes() res.text() }
Tips
- Install the same plugins your production app uses so tests exercise CORS, auth, and content negotiation.
- Prefer small pure handlers plus a thin
fn app() -> Appfactory shared by binary and tests. - Failures at startup (duplicate routes, missing static root) surface when
you call
.build()/.start()— keep that in CI.