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

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

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

Начать курс

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

Rust — язык системного программирования, который уделяет огромное внимание надёжности и безопасности кода. Встроенная система тестирования позволяет разработчикам писать unit-тесты, интеграционные тесты и документационные тесты без установки дополнительных библиотек. Однако для сложных сценариев — параметризации, генерации случайных данных или мокирования — сообщество Rust создало мощные фреймворки. В этой статье мы разберём ключевые инструменты тестирования в Rust.

Встроенный модуль test

Rust поставляется со встроенным модулем test, который активируется через атрибут #[test]. Для запуска тестов используется команда cargo test. Пример простого unit-теста:

// src/lib.rs
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

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

    #[test]
    fn test_add() {
        assert_eq!(add(2, 2), 4);
    }

    #[test]
    fn test_add_negative() {
        assert_eq!(add(-1, 1), 0);
    }
}

Ключевые возможности встроенного модуля:

  • Атрибуты: #[test], #[ignore], #[should_panic].
  • Макросы утверждений: assert!, assert_eq!, assert_ne!.
  • Интеграционные тесты: размещаются в папке tests/ и тестируют публичный API.
  • Документационные тесты: примеры кода в doc-комментариях, проверяемые через cargo test.

Для большинства проектов этого достаточно. Но когда требуется параметризация, генерация случайных данных или моки, на помощь приходят специализированные фреймворки.

Фреймворк rstest — параметризованные тесты

Библиотека rstest предоставляет мощный механизм параметризации тестов, аналогичный pytest в Python. Она позволяет задавать несколько наборов входных данных и ожидаемых результатов без дублирования кода.

Установка:

[dev-dependencies]
rstest = "0.22"

Пример параметризованного теста:

use rstest::rstest;

#[rstest]
#[case(1, 2, 3)]
#[case(0, 0, 0)]
#[case(-1, 1, 0)]
fn test_add(#[case] a: i32, #[case] b: i32, #[case] expected: i32) {
    assert_eq!(add(a, b), expected);
}

Возможности rstest:

  • Параметризация через #[case].
  • Генерация случайных данных через #[random].
  • Контекстные фикстуры через #[fixture].
  • Поддержка асинхронных тестов.

Этот фреймворк особенно полезен при тестировании математических функций, парсеров или алгоритмов, где нужно проверить множество граничных случаев.

Property-based testing с proptest

Property-based testing (тестирование на основе свойств) — метод, при котором вы описываете инварианты (свойства), которые должны выполняться для всех возможных входных данных. Библиотека proptest генерирует случайные входные данные и проверяет эти свойства.

Установка:

[dev-dependencies]
proptest = "1.5"

Пример: проверка, что сортировка сохраняет длину и все элементы:

use proptest::prelude::*;

proptest! {
    #[test]
    fn test_sort_keeps_elements(mut vec: Vec<i32>) {
        let original_len = vec.len();
        let mut sorted = vec.clone();
        sorted.sort();
        assert_eq!(sorted.len(), original_len);
        for item in &vec {
            assert!(sorted.contains(item));
        }
    }
}

Преимущества proptest:

  • Автоматическая генерация тысяч случайных сценариев.
  • Минимизация (shrink) — при падении теста библиотека находит минимальный пример, вызывающий ошибку.
  • Поддержка сложных структур данных через комбинаторы.
  • Интеграция с rstest и другими фреймворками.

Property-based testing незаменим для тестирования парсеров, сериализации, криптографических функций и любых алгоритмов, где сложно перебрать все возможные случаи вручную.

Мокирование с mockall

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