Testowanie jednostkowe w Rust jest wbudowane w sam język dzięki wbudowanym makrom, specjalnym atrybutom i infrastrukturze cargo. Historycznie, w C i wielu innych językach testowanie to zewnętrzna nakładka, co prowadzi do rozbieżności między interfejsem kodu produkcyjnego a testami. W Rust testy są kompilowane i uruchamiane w tym samym środowisku co główny kod, co eliminuje problem "działa tylko w testach".
Problem: testy mogą spowolnić kompilację, być mało informatywne lub źle zorganizowane; źle odseparowane testy utrudniają utrzymanie kodu i jego czytelność.
Rozwiązanie: testy są pisane jako specjalne funkcje oznaczone atrybutem #[test] wewnątrz modułu mod tests. Cały kod testowy jest kompilowany i uruchamiany tylko z kluczem cargo test, z kompilacji produkcyjnej jest wykluczany. Makra typu assert_eq!, should_panic oraz metody setup są używane w celu zwiększenia efektywności i czystości testowania.
Przykład kodu:
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); } }
Kluczowe cechy:
cargo test, nie trafiają do binarnego wydaniaCzy konieczne jest umieszczanie testów tylko w zagnieżdżonym module mod tests?
Nie jest to konieczne, ale jest to przyjęte dla izolacji testów i zapobiegania wyciekom kodu testowego do wydania. Ułatwia to także użycie #[cfg(test)].
Czy można uruchamiać testy tylko w określonym module/pliku?
Tak, można podać nazwę testu lub ścieżkę do niego za pomocą cargo test nazwa.
Czy testowane są funkcje prywatne?
Tak, jeśli moduł testowy jest zdefiniowany w tym samym pliku i używa use super::*;, testy mają dostęp do wszystkich wewnętrznych funkcji tego pliku.
Testy są zmieszane z głównym kodem, nie są ukryte w #[cfg(test)], używają globalnych zmiennych do inicjalizacji.
Zalety:
Wady:
Testy są inkapsulowane w zagnieżdżonych modułach, używają funkcji setup i makr assert_eq! do weryfikacji.
Zalety:
Wady: