Найти в Дзене
Один Rust не п...Rust

Как тестировать с ML

t.me/oneRustnoqRust - Реализовать систему автоматизированной генерации и оптимизации тестов: Обучение и генерация синтетических данных. Генерация тестов. Предсказание багов (заглушка в примере, в реальности — на реальных фичах). Обнаружение аномалийОбучает VAE на "нормальных" данных.
Вычисляет reconstruction error. Адаптивный анализСчитает изменения в git.
Измеряет время выполнения cargo test. Feedback loop. Визуализация. - Увеличить надежность, производительность и удобство тестирования. Модульные тесты проверяют предлагаемые функции или модули на уровне их минимальной функциональности. Обычно такие тесты хранятся в том же файле, что и тестируемый код, внутри модуля #[cfg(test)]. #[cfg(test)] mod tests { #[test] fn it_works() { assert_eq!(2 + 2, 4); } } Интеграционные тесты проверяют взаимодействие между различными модулями или компонентами программы. Эти тестовые проекты рассматриваются как отдельные tests/в корне. // tests/integration_test.rs extern crate my_p
Оглавление
nicktretyakov1/test_ML | Gitverse
ML на RUST без заморочек

t.me/oneRustnoqRust

Для чего нужна данная статья? :

- Реализовать систему автоматизированной генерации и оптимизации тестов:

Обучение и генерация синтетических данных.

Генерация тестов.

Предсказание багов (заглушка в примере, в реальности — на реальных фичах).

Обнаружение аномалийОбучает VAE на "нормальных" данных.
Вычисляет reconstruction error.

Адаптивный анализСчитает изменения в git.
Измеряет время выполнения cargo test.

Feedback loop.

Визуализация.

Зачем Вам это уметь? :

- Увеличить надежность, производительность и удобство тестирования.

Основные виды тестирования

1. Модульное тестирование (Unit Testing)

Модульные тесты проверяют предлагаемые функции или модули на уровне их минимальной функциональности. Обычно такие тесты хранятся в том же файле, что и тестируемый код, внутри модуля #[cfg(test)].

#[cfg(test)]

mod tests {

#[test] fn it_works() {

assert_eq!(2 + 2, 4);

} }

2. Интеграционное тестирование

Интеграционные тесты проверяют взаимодействие между различными модулями или компонентами программы. Эти тестовые проекты рассматриваются как отдельные tests/в корне.

// tests/integration_test.rs

extern crate my_project;

#[test] fn test_integration() {

assert_eq!(my_project::add(2, 3), 5);

}

3. Документированное тестирование (Doc Testing)

Документированные тесты проверяют код кода, написанный в документации (например, в комментариях ///). Такие тесты автоматически проверяют корректность приведенных примеров.

/// Adds two numbers together.

///

/// # Examples

///

/// ```

/// let result = my_crate::add(2, 3);

/// assert_eq!(result, 5);

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

4. Тестирование производительности (Benchmarks)

В версии Rust, начиная с 1.64, поддержка бенчмарков находится в экспериментальном состоянии (нестабильно). Бенчмарки измеряют производительность отдельных функций. Для этого используется флаг #![feature(test)].

#![feature(test)] extern crate test;

#[bench] fn bench_add(b: &mut test::Bencher) {

b.iter(|| 2 + 2);

}

5. Регрессионное тестирование (Регрессионное тестирование).

Это тесты, которые создаются для проверки исправленных ошибок. Цель таких испытаний — убедиться, что ошибка не возникнет снова в будущем.

#[test] fn regression_test_for_issue_123()

{
assert_eq!(my_function(), expected_value);

}

6. Параметризованное тестирование

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

#[test] fn test_with_parameters()

{
let test_cases = vec![(2, 3, 5), (1, 1, 2), (10, 10, 20)];

for (a, b, expected) in test_cases

{
assert_eq!(my_function(a, b), expected);

}

}

7. Тестирование использования макросов (Test Harnesses)

Для настройки и запуска тестов в Rust используется встроенная система тестов (тестовая обвязка), которая обрабатывает аннотации #[test]. Существует возможность писать собственные тестовые фреймворки на основе макросов.

8. Кастомные тесты

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

9. Тестирование с использованием cargo miri

Это инструмент для программ на Rust, который может выявить проблемы с безопасностью памяти (например, использование освобожденной памяти).

10. Фаззинг (Fuzzing)

Фаззинг — это метод тестирования с передачей случайных данных для выявления неожиданных событий программы. Для Rust существует библиотека для фаззинга — Cargo-Fuzz .

cargo fuzz init

11. Тестирование на основе свойств (Тестирование на свойствах)

Тестирование свойств последних инвариантов или свойств кода на различных случайных данных. Для этого в Rust можно использовать компонент быстрой проверки .

#[macro_use] extern crate quickcheck;

quickcheck!

{

fn prop_addition_commutative(a: i32, b: i32) -> bool

{ a + b == b + a

} }

Общая структура проекта тестирования с ML

testgen.rs — AdvancedTestGenerator (ядро генерации тестов)

Этот модуль отвечает за автоматическую генерацию unit-тестов на основе анализа AST кода (с помощью syn) и ML-руководства (вероятность багов + аномальность входов).

Trait TestGenerator

  • Interface Segregation + Dependency Inversion: маленький интерфейс, зависимости только от абстракций.
    Send + Sync — для thread-safe DI через Arc<Mutex<>>.

Struct AdvancedTestGenerator
Хранит зависимости через DI

  • Single Responsibility: только генерация тестов.
    Dependency Inversion: получает ML-модели через traits, а не конкретные типы.

Вспомогательные структуры и функцииFunctionInfo — DTO для информации о функции (имя, параметры, тип возврата, фичи).

  • ComplexityVisitor — Visitor-паттерн (syn::visit::Visit) для вычисления цикломатической сложности.
  • Извлекает метрики: количество параметров, сложность, приблизительное LOC.
    Open/Closed: легко добавить новые метрики, не меняя существующий код.
  • Поддержка типов (is_supported_primitive, type_to_literal_cast):Фильтрует только примитивы (i32, i64, f32, f64).
    Преобразует значения из тензора в Rust-литералы с кастом.

Основной метод: generate_tests

Поток выполнения (шаг за шагом):

Парсинг кода

  • Извлекает все fn из файла.

Фильтрация и сбор информацииПропускает функции с неподдерживаемыми типами параметров.
Собирает FunctionInfo + фичи (для ML).

ML:Предсказание вероятности багов

  • Для каждой функции вычисляется вероятность бага.
  • Количество генерируемых тестов пропорционально этой вероятности:

ML:Ранжирование синтетических входов по аномальности

  • Берёт наиболее аномальные входы (из VAE) — они с большей вероятностью найдут edge-кейсы.

Генерация тестов
Для каждой функции и выбранного входа:Извлекает значения из тензора (input_row.i(i).double_value()).
Генерирует литералы.
Создаёт тест с:catch_unwind — проверка на панику.
Для f32/f64 — проверка на NaN/inf.
Использует quote! для code generation.

Возврат
Возвращает Vec<TokenStream> — готовые токены для вставки в файл тестов.

main.rs — Оркестратор и точка входа

Traits для всех подсистем
Определены 8 traits (SyntheticDataGenerator, BugPredictor, TestGenerator, ...).
Все Send + Sync для параллелизма и DI.

Конкретные реализацииWGAN_GP → генерация данных.
MLPBugPredictor → предсказание багов.
VariationalAutoencoder → аномалии.
GitChangeDetector, SimplePerformanceAnalyzer, JsonFeedbackCollector, PlottersDashboardVisualizer.

Builder-паттерн с DI

  • Open/Closed + Dependency Inversion: легко добавлять/заменять компоненты.
    Некоторые компоненты имеют default (например, GitChangeDetector).

Struct TestAutomationOrchestrator
Хранит все компоненты через Shared<T> = Arc<Mutex<T>>.

Метод run() — основной цикл автоматизации