Mini-Project - Testing & Refinement

1. Welcome and Icebreaker:

What’s the most satisfying bug you’ve ever fixed?

2. Outline the Session:

Agenda:

  1. Concept Explanation: Testing and refining your mini-project.
  2. Live Coding: Write integration tests and refactor code.
  3. Tasks: Practice by improving your project’s quality.

Learning Outcomes:

  • Write integration tests for your API endpoints.
  • Refactor code for clarity and efficiency.
  • Add input validation.

Expectations: Try testing all endpoints and refactoring for best practices!

3. Concept Explanation:

Testing and refinement are crucial for a robust API. Write integration tests to ensure endpoints work as expected. Refactor code for maintainability and add input validation for safety.

4. Live Coding Demonstration:

// In-process router test for POST /todos; use the database-backed
// create_todo handler from Day 27 and a disposable test SQLite database.
#[cfg(test)]
mod tests {
    use super::*;
    use axum::{body::Body, http::{Request, StatusCode}, routing::post, Router};
    use tower::ServiceExt;

    #[tokio::test]
    async fn test_create_todo() {
        let pool = sqlx::sqlite::SqlitePoolOptions::new()
            .max_connections(1)
            .connect("sqlite::memory:").await.unwrap();
        sqlx::query("CREATE TABLE todos (id INTEGER PRIMARY KEY, title TEXT NOT NULL)")
            .execute(&pool).await.unwrap();
        let app = Router::new().route("/todos", post(create_todo)).with_state(pool);
        let request = Request::builder()
            .method("POST").uri("/todos")
            .header("content-type", "application/json")
            .body(Body::from(r#"{"title":"Test"}"#)).unwrap();
        let resp = app.oneshot(request).await.unwrap();
        assert_eq!(resp.status(), StatusCode::CREATED);
    }
}

Add tower = { version = "0.5", features = ["util"] }. For isolated in-memory SQLite tests use a pool with max_connections(1) (or a temporary file), since separate SQLite in-memory connections have separate schemas.

Best Practices:

  • Test all endpoints, including error cases.
  • Refactor for readability and maintainability.
  • Validate all user input.

Common Pitfalls:

  • Not testing edge cases.
  • Skipping input validation.

5. Tasks

  • Write tests for all CRUD endpoints.
  • Refactor code for clarity and efficiency.
  • Add input validation using the validator crate.