36
loading...
This website collects cookies to deliver better user experience
surf
as dev-dependency[dev-dependencies]
surf = "2.1.0"
(...)
let res = surf::Client::with_http_client(app)
.get("https://example.com/dinos")
.await?;
assert_eq!(200, res.status());
(...)
let mut res = surf::Client::with_http_client(app)
.post("https://example.com/dinos")
.body(serde_json::to_string(&dino)?)
.await?;
❯ cargo test
Finished test [unoptimized + debuginfo] target(s) in 0.20s
Running target/debug/deps/tide_basic_crud-1a926f88350611fd
running 5 tests
test tests::list_dinos ... ok
test tests::create_dino ... ok
test tests::delete_dino ... ok
test tests::get_dino ... ok
test tests::update_dino ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
assert-json-diff
that add two macros:assert_json_eq
: macro used to compare two JSON values for an exact match.assert_json_include
: macro used to compare two JSON values for an inclusive match.get_dino
testlet d: Dino = res.body_json().await?;
assert_json_eq!(dino, d);
json asserts
...❯ cargo test
Finished test [unoptimized + debuginfo] target(s) in 1.44s
Running target/debug/deps/tide_basic_crud-1a926f88350611fd
running 5 tests
test tests::list_dinos ... ok
test tests::create_dino ... ok
test tests::delete_dino ... ok
test tests::get_dino ... ok
test tests::update_dino ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
TODOs
before finish the improvements. First, we need to clear the dinos
table before run each test since we always want to create an isolated test case. To accomplish that, let's create a module (mod
) in our main file for the tests and add a helper function to clear the dinos
table.#[cfg(test)]
mod tests {
use super::*;
use lazy_static::lazy_static;
use sqlx::query;
async fn clear_dinos() -> Result<(),Box<dyn std::error::Error>> {
let db_pool = make_db_pool(&DB_URL).await;
sqlx::query("DELETE FROM dinos").execute(&db_pool).await?;
Ok(())
}
(...)
clear_dinos
before make any change/request.#[async_std::test]
async fn create_dino() -> tide::Result<()> {
dotenv::dotenv().ok();
clear_dinos().await.expect("Failed to clear the dinos table");
(...)
ci
(gh actions) to run the tests. For that we set a new block in ci.yml
to run those tests- name: Run test
run: cargo test
env:
DATABASE_URL: postgres://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/tide
?
here will bubble the error to the caller.let row : Dino = match query_as!(
Dino,
r#"
INSERT INTO dinos (id, name, weight, diet) VALUES
($1, $2, $3, $4) returning id, name, weight, diet
"#,
dino.id,
dino.name,
dino.weight,
dino.diet
)
.fetch_one(&db_pool)
.await {
Ok( r) => r,
Err( e ) => {
// TODO: we may want to cast the error here.
let err = Error::new(409,e);
return Err(err);
}
};
(...)
let res = surf::Client::with_http_client(app)
.delete(format!("https://example.com/dinos/{}", &Uuid::new_v4()))
.await?;
assert_eq!(404, res.status());
Tide v0.15.0 introduces a new way to start servers: Server::bind. This enables separating "open the socket" from "start accepting connections" which Server::listen does for you in a single call.
[dependencies]
tide = "0.15.0"
async-std = { version = "1.7.0", features = ["attributes"] }
#[async_std::main]
async fn main() {
dotenv::dotenv().ok();
tide::log::start();
let db_url = std::env::var("DATABASE_URL").unwrap();
let db_pool = make_db_pool(&db_url).await;
let app = server(db_pool).await;
let mut listener = app.bind("127.0.0.1:8080").await.expect("can't bind the port");
for info in listener.info().iter() {
println!("Server listening on {}", info);
}
listener.accept().await.unwrap();
}
tera
as render engine but will cover that in the next post
and keep this one focused in tests.