From 0ad02ee0e02c235b49a181bd164cc945fde18b18 Mon Sep 17 00:00:00 2001 From: Tore Pettersen Date: Sun, 5 Apr 2020 21:12:44 +0200 Subject: [PATCH] Add convenience functions for testing (#1401) * Add convenience functions for testing * Fix remarks from PR and add tests * Add unpin to read_json_body * Update changelog --- CHANGES.md | 1 + src/test.rs | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 0739f280c..4a7862543 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,7 @@ ### Added * Add helper function for creating routes with `TRACE` method guard `web::trace()` +* Add convenience functions `test::read_body_json()` and `test::TestRequest::send_request()` for testing. ### Changed diff --git a/src/test.rs b/src/test.rs index 15e66a230..19ea8bbef 100644 --- a/src/test.rs +++ b/src/test.rs @@ -203,6 +203,54 @@ where bytes.freeze() } +/// Helper function that returns a deserialized response body of a ServiceResponse. +/// +/// ```rust +/// use actix_web::{App, test, web, HttpResponse, http::header}; +/// use serde::{Serialize, Deserialize}; +/// +/// #[derive(Serialize, Deserialize)] +/// pub struct Person { +/// id: String, +/// name: String, +/// } +/// +/// #[actix_rt::test] +/// async fn test_post_person() { +/// let mut app = test::init_service( +/// App::new().service( +/// web::resource("/people") +/// .route(web::post().to(|person: web::Json| async { +/// HttpResponse::Ok() +/// .json(person.into_inner())}) +/// )) +/// ).await; +/// +/// let payload = r#"{"id":"12345","name":"User name"}"#.as_bytes(); +/// +/// let resp = test::TestRequest::post() +/// .uri("/people") +/// .header(header::CONTENT_TYPE, "application/json") +/// .set_payload(payload) +/// .send_request(&mut app) +/// .await; +/// +/// assert!(resp.status().is_success()); +/// +/// let result: Person = test::read_body_json(resp).await; +/// } +/// ``` +pub async fn read_body_json(res: ServiceResponse) -> T +where + B: MessageBody + Unpin, + T: DeserializeOwned, +{ + let body = read_body(res).await; + + serde_json::from_slice(&body) + .unwrap_or_else(|_| panic!("read_response_json failed during deserialization")) +} + pub async fn load_stream(mut stream: S) -> Result where S: Stream> + Unpin, @@ -527,6 +575,16 @@ impl TestRequest { (req, payload) } + + /// Complete request creation, calls service and waits for response future completion. + pub async fn send_request(self, app: &mut S) -> S::Response + where + S: Service, Error = E>, + E: std::fmt::Debug + { + let req = self.to_request(); + call_service(app, req).await + } } /// Start test server with default configuration @@ -1041,6 +1099,23 @@ mod tests { assert_eq!(result, Bytes::from_static(b"welcome!")); } + #[actix_rt::test] + async fn test_send_request() { + let mut app = + init_service(App::new().service(web::resource("/index.html").route( + web::get().to(|| async { HttpResponse::Ok().body("welcome!") }), + ))) + .await; + + let resp = TestRequest::get() + .uri("/index.html") + .send_request(&mut app) + .await; + + let result = read_body(resp).await; + assert_eq!(result, Bytes::from_static(b"welcome!")); + } + #[derive(Serialize, Deserialize)] pub struct Person { id: String, @@ -1068,6 +1143,28 @@ mod tests { assert_eq!(&result.id, "12345"); } + #[actix_rt::test] + async fn test_body_json() { + let mut app = init_service(App::new().service(web::resource("/people").route( + web::post().to(|person: web::Json| { + async { HttpResponse::Ok().json(person.into_inner()) } + }), + ))) + .await; + + let payload = r#"{"id":"12345","name":"User name"}"#.as_bytes(); + + let resp = TestRequest::post() + .uri("/people") + .header(header::CONTENT_TYPE, "application/json") + .set_payload(payload) + .send_request(&mut app) + .await; + + let result: Person = read_body_json(resp).await; + assert_eq!(&result.name, "User name"); + } + #[actix_rt::test] async fn test_request_response_form() { let mut app = init_service(App::new().service(web::resource("/people").route(