liveBook · Manning

Unit test

As explained in Rust Servers, Services, and Apps

A unit test is an automated test that checks the behavior of a small, isolated program component.

A unit test invokes a small part of a Rust web application and checks its behavior. Tests here exercise HTTP handlers directly or verify individual HTTP parsing and response-building functions. section 7.6 section 2.3.1

A handler test can:

  • Construct request parameters and application state, invoke the handler, and check its response. section 4.3.4
  • Check status codes, parsed request fields, or the serialized form of an HTTP response. section 2.3.1 section 2.3.2
  • Run tests with Cargo; passing tests only verify the behavior actually implemented, so unconditional success responses can pass before database logic exists. section 4.3.4

Test a handler directly

For a POST handler, create form parameters and template state, call the handler, then assert that the response status is OK. This tests the handler function without simulating a client request through the application; that is treated as integration testing. section 7.6

Listing 4.5 Unit tests for the handler functions
#[cfg(test)]
mod tests {
   use super::*;                                                           #1
   use actix_web::http::StatusCode;
   use chrono::NaiveDate;
   use dotenv::dotenv;
   use sqlx::postgres::PgPool;
   use std::env;
   use std::sync::Mutex;
 
   #[actix_rt::test]
   async fn get_all_courses_success() {
       dotenv().ok();
       let database_url = env::var("DATABASE_URL").expect(
       "DATABASE_URL is not set in .env file");                          #2
       let pool: PgPool = PgPool::connect(&database_url).await.unwrap();   #3
       let app_state: web::Data<AppState> = web::Data::new(AppState {      #4
           health_check_response: "".to_string(),
           visit_count: Mutex::new(0),
           db: pool,
       });
       let tutor_id: web::Path<(i32,)> = web::Path::from((1,));            #5
       let resp = get_courses_for_tutor(app_state, tutor_id).await;        #6
       assert_eq!(resp.status(), StatusCode::OK);                          #7
   }
 
   #[actix_rt::test]
   async fn get_course_detail_test() {
       dotenv().ok();
       let database_url = env::var("DATABASE_URL").expect(
       "DATABASE_URL is not set in .env file");
       let pool: PgPool = PgPool::connect(&database_url).await.unwrap();
       let app_state: ...                                                  #8
       let params: web::Path<(i32, i32)> = web::Path::from((1, 2));        #8
       let resp = get_course_details(app_state, params).await;             #8
       assert_eq!(resp.status(), StatusCode::OK);                          #8
   }                                                                       #8
 
   #[actix_rt::test]                                                       #8
   async fn post_course_success() {                                        #8
       dotenv().ok();                                                      #8
       let database_url = env::var("DATABASE_URL").expect(                 #8
       "DATABASE_URL is not set in .env file");                          #8
       let pool: PgPool = PgPool::connect(&database_url).await.unwrap();   #8
       let app_state: ...                                                  #8
       let new_course_msg = Course {
           course_id: 1,
           tutor_id: 1,
           course_name: "This is the next course".into(),
           posted_time: Some(NaiveDate::from_ymd(2020, 9, 17).and_hms(
           14, 01, 11)),
       };
       let course_param = web::Json(new_course_msg);
       let resp = post_new_course(course_param, app_state).await;
       assert_eq!(resp.status(), StatusCode::OK);
   }
}

See the handler test listing for examples that build application state and invoke handlers for three API operations. section 4.3.4

How Rust Servers, Services, and Apps covers it

How deep it goes
Works through test setup, direct invocation, and assertions; contrasts direct handler tests with integration tests but does not develop database logic in the interim example.
Examples
Uses course API handlers, tutor form submissions, HTTP request parsing, and response status and serialization assertions.
What it assumes
Assumes familiarity with handler signatures and Rust project structure; demonstrates constructing test parameters and application state.
What you can do after
Evaluate handler behavior by invoking functions directly and asserting responses, or test HTTP parsing and response formatting with Cargo.
How it connects
Connects unit tests to HTTP handlers, integration testing, request parsing, and HTTP response serialization.

Also explained in

Compare how 9 books explain unit test →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust Servers, Services, and Apps. The section links point to the parts of the book it draws on.