Модульное тестирование в Rust встроено в сам язык через встроенные макросы, специальные атрибуты и инфраструктуру cargo. Исторически в C и ряде других языков тестирование — внешняя надстройка, что приводит к расхождению интерфейса продакшн-кода и тестов. В Rust тесты компилируются и запускаются в том же окружении, что и основной код, что устраняет проблему "работает только в тестах".
Проблема: тесты могут замедлять сборку, быть неинформативными или плохо организованными; также плохо обособленные тесты мешают сопровождению кода и его читаемости.
Решение: тесты пишутся как специальные функции помеченные атрибутом #[test] внутри модуля mod tests. Весь тестовый код компилируется и запускается только с ключом cargo test, из продакшн-сборки он исключается. Макросы типа assert_eq!, should_panic и setup-методы используются для повышения эффективности и чистоты тестирования.
Пример кода:
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); } }
Ключевые особенности:
cargo test, не попадают в релизный бинарникОбязательно ли помещать тесты только во вложенный модуль mod tests?
Не обязательно, но это принято для изоляции тестов и предотвращения утечек тестового кода в релиз. Также помогает использовать #[cfg(test)].
Можно ли запускать тесты только на определённом модуле/файле?
Да, можно указывать имя теста или путь к нему с помощью cargo test имя.
Тестируются ли приватные функции?
Да, если тестовый модуль определён внутри того же файла и использует use super::*;, тесты имеют доступ ко всем внутренним функциям этого файла.
Тесты смешаны с основным кодом, не спрятаны в #[cfg(test)], используют глобальные переменные для инициализации.
Плюсы:
Минусы:
Тесты инкапсулированы во вложенных модулях, используются setup-функции и макросы assert_eq! для проверки.
Плюсы:
Минусы: