考慮到我們的 Web Server 有多個功能,例如產生 QR Code、驗證顏色碼、從地址獲取經緯度等,整合測試將確保所有這些部分能夠正確地一起工作。
我們的 index()
和 generate_svg()
分別負責處理 HTTP GET 和 POST 請求。這些函式調用了多個其他函式,如 get_code_data()
和 get_coordinates()
,因此它們是整合測試的理想目標。
我們可以使用 actix_web::test
來模擬 HTTP 請求。
#[cfg(test)]
mod integration_tests {
use super::*;
use actix_web::http::StatusCode;
use actix_web::{test, App};
use serde_json::json;
#[actix_rt::test]
async fn test_index() {
let mut app = test::init_service(
App::new().service(index),
)
.await;
let req = test::TestRequest::get()
.uri("/generate_qr?email=bucky0112@gmail.com")
.to_request();
let resp = test::call_service(&mut app, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
#[actix_rt::test]
async fn test_generate_svg_function() {
let mut app = test::init_service(
App::new().service(generate_svg),
)
.await;
let payload = json!({
"url": "https://example.com",
});
let req = test::TestRequest::post()
.uri("/generate_qr_svg")
.set_json(&payload)
.to_request();
let resp = test::call_service(&mut app, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
}
然後還需要在 models/mod.rs 加上:
#[derive(serde::Deserialize, serde::Serialize)]
pub struct Info {
pub url: Option<String>,
pub phone: Option<String>,
pub email: Option<String>,
pub address: Option<String>,
pub foreground: Option<String>,
pub background: Option<String>,
pub dimension: Option<u32>,
}
接著跑測試 cargo test
出來的結果是:
❯ cargo test
Compiling qrcode-actix v0.1.0 (/Users/buckychu/sideProjects/qrcode-actix)
Finished test [unoptimized + debuginfo] target(s) in 2.79s
Running unittests src/main.rs (target/debug/deps/qrcode_actix-f5c31d729f1fd710)
running 5 tests
test api::tests::test_get_coordinates ... ok
test api::tests::test_get_code_data ... ok
test api::tests::test_is_valid_color ... ok
test api::integration_tests::test_index ... FAILED
test api::integration_tests::test_generate_svg_function ... ok
failures:
---- api::integration_tests::test_index stdout ----
thread 'api::integration_tests::test_index' panicked at 'assertion failed: `(left == right)`
left: `400`,
right: `200`', src/api/mod.rs:267:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
api::integration_tests::test_index
test result: FAILED. 4 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
根據測試結果,test_index
測試失敗了,因為它期望得到的 HTTP 狀態碼是 200 OK,但實際得到的是 400 Bad Request。看起來我們要測試 email 但是失敗了,因為我們之前似乎都忘了在 index()
加入新的參數。
所以我們先更改一下測試:
#[cfg(test)]
mod integration_tests {
use super::*;
use actix_web::http::StatusCode;
use actix_web::{test, App};
use serde_json::json;
#[actix_rt::test]
async fn test_index() {
let mut app = test::init_service(App::new().service(index)).await;
let req = test::TestRequest::get()
.uri("/generate_qr?url=https://example.com")
.to_request();
let resp = test::call_service(&mut app, req).await;
assert_eq!(resp.status(), StatusCode::OK);
}
}
這樣測試結果沒問題,全部的測試都通過。🎉
❯ cargo test
Compiling qrcode-actix v0.1.0 (/Users/buckychu/sideProjects/qrcode-actix)
Finished test [unoptimized + debuginfo] target(s) in 2.70s
Running unittests src/main.rs (target/debug/deps/qrcode_actix-f5c31d729f1fd710)
running 5 tests
test api::tests::test_get_code_data ... ok
test api::tests::test_get_coordinates ... ok
test api::tests::test_is_valid_color ... ok
test api::integration_tests::test_generate_svg_function ... ok
test api::integration_tests::test_index ... ok
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
然後原本的 index()
也做一下修正,可以加入其他的參數,例如 email
。
#[get("/generate_qr")]
async fn index(data: web::Query<Info>) -> HttpResponse {
let code_data = match get_code_data(&data).await {
Some(data) => data,
None => return HttpResponse::BadRequest().body("缺少有效數據"),
};
let code = match QrCode::new(code_data) {
Ok(c) => c,
Err(_) => return HttpResponse::BadRequest().body("你輸入的字串無法處理"),
};
let image = code.render::<Luma<u8>>().build();
let mut buffer = Vec::new();
match DynamicImage::ImageLuma8(image).write_to(&mut buffer, image::ImageOutputFormat::Png) {
Ok(_) => (),
Err(_) => return HttpResponse::InternalServerError().body("無法生成圖像"),
}
HttpResponse::Ok().content_type("image/png").body(buffer)
}
現在 index()
也可以產生其他的 QR code 了,明天我們持續做好測試的部分。