1. 単体テスト
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 { Err("Division by zero".into()) } else { Ok(a / b) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn test_divide() {
assert_eq!(divide(10.0, 2.0), Ok(5.0));
}
#[test]
fn test_divide_by_zero() {
assert!(divide(10.0, 0.0).is_err());
}
#[test]
#[should_panic(expected = "overflow")]
fn test_overflow() {
let _ = i8::MAX.checked_add(1).expect("overflow");
}
}
2. rstest — フィクスチャとパラメータ化
use rstest::*;
#[fixture]
fn db_pool() -> PgPool {
// Setup test database
PgPoolOptions::new().connect_lazy("postgres://test:test@localhost/test").unwrap()
}
#[rstest]
#[case(2, 3, 5)]
#[case(0, 0, 0)]
#[case(-1, 1, 0)]
fn test_add_parametrized(#[case] a: i32, #[case] b: i32, #[case] expected: i32) {
assert_eq!(add(a, b), expected);
}
// Async test
#[rstest]
#[tokio::test]
async fn test_create_product(db_pool: PgPool) {
let repo = ProductRepository::new(db_pool);
let product = repo.create("Test", 9.99, None).await.unwrap();
assert_eq!(product.name, "Test");
}
3. モックルによるモック化
use mockall::{automock, predicate::*};
#[automock]
trait UserRepository {
async fn find_by_id(&self, id: &str) -> Option<User>;
async fn save(&self, user: &User) -> Result<(), String>;
}
#[tokio::test]
async fn test_user_service() {
let mut mock = MockUserRepository::new();
mock.expect_find_by_id()
.with(eq("user-1"))
.times(1)
.returning(|_| Some(User { id: "user-1".into(), name: "Alice".into() }));
let service = UserService::new(mock);
let user = service.get_user("user-1").await.unwrap();
assert_eq!(user.name, "Alice");
}
4. 基準ベンチマーク
// benches/my_bench.rs
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn fibonacci(n: u64) -> u64 {
match n {
0 | 1 => n,
_ => { let (mut a, mut b) = (0, 1); for _ in 2..=n { let t = a + b; a = b; b = t; } b }
}
}
fn bench_fibonacci(c: &mut Criterion) {
c.bench_function("fib 20", |b| b.iter(|| fibonacci(black_box(20))));
let mut group = c.benchmark_group("fibonacci");
for n in [10, 20, 30, 40] {
group.bench_with_input(format!("fib {}", n), &n, |b, &n| {
b.iter(|| fibonacci(black_box(n)));
});
}
group.finish();
}
criterion_group!(benches, bench_fibonacci);
criterion_main!(benches);
cargo bench
cargo test
cargo test -- --test-threads=1 # Sequential
cargo tarpaulin --out Html # Coverage
次の記事: Rust 用の Docker と CI/CD。