Тестирование в Rust: фреймворки и инструменты
Rust — язык системного программирования, который уделяет огромное внимание надёжности и безопасности. Встроенная система тестирования — одна из ключевых особенностей, позволяющая писать качественный код без необходимости устанавливать сторонние фреймворки. В этой статье мы подробно рассмотрим основные инструменты для тестирования в Rust: от простых unit-тестов до сложных property-based тестов и бенчмарков.
Встроенный фреймворк тестирования
В Rust тесты запускаются с помощью команды cargo test. Тесты — это обычные функции, помеченные атрибутом #[test]. Фреймворк автоматически собирает все такие функции в вашем проекте и запускает их.
Unit-тесты
Unit-тесты обычно располагаются в том же файле, что и тестируемый код, в отдельном модуле tests. Это позволяет тестировать приватные функции.
// src/lib.rs
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
fn private_helper(x: i32) -> i32 {
x * 2
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn test_private_helper() {
assert_eq!(private_helper(5), 10);
}
}
Запуск: cargo test
Интеграционные тесты
Интеграционные тесты находятся в директории tests/ на уровне корня проекта. Каждый файл в этой папке — отдельный крейт, который тестирует ваш публичный API.
// tests/integration_test.rs
use my_crate::add;
#[test]
fn test_add_integration() {
assert_eq!(add(10, 20), 30);
}
Макросы для проверок
Rust предоставляет несколько встроенных макросов для написания проверок:
assert!(expression)— паникует, если выражение ложно.assert_eq!(left, right)— проверяет равенство с помощьюPartialEq.assert_ne!(left, right)— проверяет неравенство.debug_assert!()— работает только в debug-сборках.
#[test]
fn test_with_assert() {
let result = some_function();
assert!(result.is_ok(), "Ожидался Ok, получено: {:?}", result);
assert_eq!(result.unwrap(), 42);
}
Doctests
Одна из самых мощных фич Rust — возможность писать тесты прямо в документации. Код внутри блоков /// или //! автоматически компилируется и запускается как тест.
/// Складывает два числа.
///
/// # Примеры
///
/// ```
/// use my_crate::add;
/// assert_eq!(add(1, 2), 3);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
Запуск: cargo test — doctests выполнятся вместе с обычными тестами.
Property-based тестирование с proptest
Библиотека proptest (аналог Hypothesis в Python или QuickCheck в Haskell) позволяет генерировать случайные входные данные и проверять инварианты.
use proptest::prelude::*;
fn reverse_string(s: &str) -> String {
s.chars().rev().collect()
}
proptest! {
#[test]
fn test_reverse_twice(s in ".*") {
let reversed = reverse_string(&s);
let double_reversed = reverse_string(&reversed);
assert_eq!(s, double_reversed);
}
}
Установка: cargo add proptest
Бенчмарки
Для измерения производительности в Rust есть стабильные бенчмарки (начиная с Rust 1.78) через cargo bench и крейт criterion для более сложных сценариев.
Встроенные бенчмарки (nightly)
#![feature(test)]
extern crate test;
#[bench]
fn bench_add(b: &mut test::Bencher) {
b.iter(|| add(1, 2));
}
Бенчмарки с criterion
use criterion::{black_box, criterion_group, criterion_main, Criterion};
fn fibonacci(n: u64) -> u64 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
fn bench_fib Также в библиотеке
Работа с S3 и облачными хранилищами в Node.js: библиотека @aws-sdk/client-s3
Event Bus и паттерн Observer в Kotlin: реализация и примеры
Генератор QR-кодов на Swift: Core Image, CIFilter и собственные решения