Search code examples
testingrustmockingmiddlewareactix-web

How can I mock/create ReqData for testing an actix web request handler?


I am trying to unit-test a request handler that uses middleware to pass data into it. Before implementing the middleware tests were fairly straightforward, I could use web::Data::new(data) to pass test data into the handler. However, now that the data is wrapped in web::ReqData I'm having trouble figuring out how to pass in data for testing.

example:

pub async fn handler(
  some_data: web::Data<SomeDataType>,
  req_data: web::ReqData<ReqestDataType>
) -> HttpResponse {
  // some code
}

#[actix_rt::test]
async fn test_fn() {
  let resp = handler(
    web::Data::new(someData),
    // what can I put here?
  ).await;
  assert_eq!(resp.status(), status_code::OKAY);
}

Solution

  • "Request-local data is arbitrary data attached to an individual request, usually by middleware. It can be set via extensions_mut on HttpRequest or ServiceRequest"

    ReqData<T> can be extracted from the HttpRequest using extract method of ReqData<T>. Refer

    How to create test HttpRequest is documented here

    With this information we create a test HttpRequest then set the ReqData using the extensions_mut method, then extract it using ReqData::extract method.

    Example:

    use actix_web::{HttpResponse, web};
    
    #[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
    pub struct User {
        id: u32,
        name: String,
    }
    
    pub async fn handler(
      some_data: web::Data<String>,
      req_data: web::ReqData<User>
    ) -> HttpResponse {
      // some code
      println!("{:?}", some_data);
      println!("{:?}", req_data);
      HttpResponse::Ok().finish()
    }
    
    #[cfg(test)]
    mod tests {
    
        use actix_web::{test, FromRequest, HttpMessage, web::ReqData};
    
        use super::*;
        #[actix_rt::test]
        async fn test_fn() {
        let http_request = test::TestRequest::default().to_http_request();
        http_request.extensions_mut().insert(User{id: 1, name: "User1".to_string()});
        let _ = handler(
            web::Data::new("Dummy data".to_string()),
            ReqData::extract(&http_request).await.unwrap()
        ).await;
        }
    }