Перейти к основному содержимому

Тестирование в Rust

Разработчику Архитектору

Тестирование в Rust

Встроенный фреймворк testing + cargo test. Для HTTP — axum::test / reqwest. Для моков трейтов — mockall или ручные fake.

База: Первая программа · Axum · подробности в справочнике.


Unit-тест в том же файле

pub fn add(a: i32, b: i32) -> i32 {
a + b
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn adds() {
assert_eq!(5, add(2, 3));
}
}
cargo test
cargo test adds -- --nocapture

Table-driven

#[test]
fn add_cases() {
let cases = [
(0, 0, 0),
(2, 3, 5),
(-1, 1, 0),
];
for (a, b, want) in cases {
assert_eq!(want, add(a, b), "add({a},{b})");
}
}

Асинхронные тесты

[dev-dependencies]
tokio = { version = "1", features = ["rt", "macros"] }
#[tokio::test]
async fn async_works() {
let result = tokio::time::timeout(
std::time::Duration::from_secs(1),
async { 42 },
)
.await
.unwrap();
assert_eq!(42, result);
}

Тест HTTP (Axum)

use axum::{routing::get, Router};
use tower::ServiceExt; // dev-dependency tower

#[tokio::test]
async fn health_returns_ok() {
let app = Router::new().route("/health", get(|| async { "ok" }));

let response = app
.oneshot(
axum::http::Request::builder()
.uri("/health")
.body(axum::body::Body::empty())
.unwrap(),
)
.await
.unwrap();

assert_eq!(200, response.status());
}

В Axum 0.7 удобнее axum::test::TestClient (см. документацию к вашей версии).


Интеграционные тесты

Файл tests/api.rs (отдельный crate root):

// use my_crate::app;

#[test]
fn integration_smoke() {
assert!(true);
}

Cargo компилирует каждый файл в tests/ как отдельный бинарник.


mockall (обзор)

use mockall::automock;

#[automock]
trait Store {
fn get(&self, id: u32) -> Option<String>;
}

Генерирует mock-реализацию для тестов.


CI

- run: cargo test --all-features
- run: cargo clippy -- -D warnings

Флаг -- -D warnings в clippy — отдельно, но часто в одном pipeline.


Связанные материалы


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).