Testing
All your testing, so far, has been manual: you've been launching the application and issuing requests to it with curl
.
Let's move away from that: it's time to write some automated tests!
Black-box testing
The preferred way to test a Pavex application is to treat it as a black box: you should only test the application through its HTTP interface. This is the most realistic way to test your application: it's how your users will interact with it, after all.
The template project includes a reference example for the /api/ping
endpoint:
use pavex::http::StatusCode;
//(1)!
use crate::helpers::TestApi;
#[tokio::test]
async fn ping_works() {
let api = TestApi::spawn().await; //(2)!
let response = api.get_ping().await; //(3)!
assert_eq!(response.status(), StatusCode::OK);
}
TestApi
is a helper struct that provides a convenient interface to interact with the application.
It's defined inserver/tests/helpers.rs
.TestApi::spawn
starts a new instance of the application in the background.TestApi::get_ping
issues an actualGET /api/ping
request to the application.
Add a new integration test
Let's write a new integration test to verify the behaviour on the happy path for GET /api/greet/:name
:
use pavex::http::StatusCode;
use crate::helpers::TestApi;
#[tokio::test]
async fn greet_happy_path() {
let api = TestApi::spawn().await;
let name = "Ursula";
let response = api
.api_client
.get(&format!("{}/api/greet/{name}", &api.api_address))
.header("User-Agent", "Test runner")
.send()
.await
.expect("Failed to execute request.");
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(response.text().await.unwrap(), "Hello, Ursula!");
}
It follows the same pattern as the ping
test: it spawns a new instance of the application, issues a request to it
and verifies that the response is correct.
Let's complement it with a test for the unhappy path as well: requests with a malformed User-Agent
header should be
rejected.
// [...]
#[tokio::test]
async fn non_utf8_user_agent_is_rejected() {
let api = TestApi::spawn().await;
let name = "Ursula";
let response = api
.api_client
.get(&format!("{}/api/greet/{name}", &api.api_address))
.header("User-Agent", b"hello\xfa".as_slice())
.send()
.await
.expect("Failed to execute request.");
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
assert_eq!(
response.text().await.unwrap(),
"The `User-Agent` header value can only use ASCII printable characters."
);
}
cargo px test
should report three passing tests now. As a bonus exercise, try to add a test for the case where the
User-Agent
header is missing.