Тестирование в Rust: фреймворки и инструменты

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Тестирование в 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                    

Рекомендаций