Testing - Integration Tests
1. Welcome and Icebreaker:
Have you ever found a bug that only showed up when multiple parts of your app worked together?
2. Outline the Session:
Agenda:
- Concept Explanation: What are integration tests and why are they important?
- Live Coding: Write in-process integration tests for Axum routes using
tower::ServiceExt. - Tasks: Practice by testing your own endpoints.
Learning Outcomes:
- Understand the purpose of integration tests in Axum projects.
- Write and run integration tests for API endpoints.
Expectations: Try testing both successful and failing requests!
3. Concept Explanation:
Integration tests check how different parts of your app work together. For a router test without a separately running server, use tower::ServiceExt::oneshot. A network-level test can use reqwest with a listener bound to port 0 and a server spawned by the test.
4. Live Coding Demonstration:
Add tower = { version = "0.5", features = ["util"] } alongside Axum 0.8 and Tokio 1. Put the test below in src/main.rs (or a library module) so it can call the root handler from Day 1:
#[cfg(test)]
mod tests {
use super::*;
use axum::{body::Body, http::{Request, StatusCode}, routing::get, Router};
use tower::ServiceExt;
#[tokio::test]
async fn test_get_root() {
let app = Router::new().route("/", get(root));
let resp = app.oneshot(Request::builder().uri("/").body(Body::empty()).unwrap())
.await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
}
Best Practices:
- Use a separate test database if needed.
- Clean up test data between runs.
Common Pitfalls:
- Not isolating tests from production data.
- Assuming a server exists at a fixed port;
oneshotdoes not require one.
5. Tasks
- Write an integration test for a POST endpoint.
- Test error responses and edge cases.
- Try collecting the response body with
http-body-utiland checking its contents.