Wszystkie testy jednostkowe w jednym pliku wykonywalnym, czy je podzielić?


12

Czy pisząc testy dla jednego oprogramowania, powiedzmy w bibliotece, wolisz skompilować wszystkie testy jednostkowe w jednym, czy też podzielić je na kilka plików wykonywalnych?

Pytam dlatego, że obecnie używam CUnit do testowania biblioteki, nad którą pracuję. Testy są podzielone na osobne pakiety, które są kompilowane w jeden plik wykonywalny z wydrukowanym wyjściem w przypadku awarii. Obecnie systemem kompilacji dla tej biblioteki jest CMake (który pomimo swojej nazwy ma niewiele wspólnego z CUnit), który ma własną platformę testową, CTest . CTest pozwala mi zarejestrować listę plików wykonywalnych, które służą jako testy.

Zastanawiam się, czy użyć CTest do zautomatyzowanych testów. Wymagałoby to jednak podzielenia testów, które do tej pory napisałem, na osobne cele kompilacji. W przeciwnym razie nie mogę tak naprawdę korzystać z niektórych zaawansowanych funkcji CTests, takich jak selektywne uruchamianie testów.

Zdaję sobie sprawę, że jest to raczej pytanie o to, jakich narzędzi użyć, a także o ich obsługę i konwencje, ale poza tym, czy istnieją inne powody, aby preferować pojedynczy plik wykonywalny testu zamiast osobnych? Lub odwrotnie?


Podziel je na osobne pliki wykonywalne według klas. Każda klasa powinna mieć swój własny test jednostkowy, chyba że klasa nie nadaje się do testowania jednostkowego, a zatem musi być testowana przez inne klasy pośrednio.
Brian

1
Jeśli masz dużą bibliotekę z setkami klas, każda z testem jednostkowym, czas kompilacji jest znacznie dłuższy, jeśli utworzysz dla nich kompletny plik binarny, w porównaniu do jednego (lub kilku) dużych plików binarnych. Poza tym jest wiele plików makefile do zarządzania, każdy z osobnymi liniami linków.
JBRWilkinson

To nie jest takie duże. Mniej niż 20 modułów. Jestem również w stanie skompilować je wszystkie z tymi samymi flagami, więc CMake może generować pliki Makefile bez dużej pracy z mojej strony.
Benjamin Kloster,

Odpowiedzi:


5

Lubię mieć zautomatyzowane testy w pojedynczych plikach binarnych lub przynajmniej w grupach dla grupy „należy do siebie”, a następnie wywoływać je z poziomu prostego skryptu powłoki (gdzie niezerowy kod wyjścia sygnalizuje awarię i wyjście na stderr może zostać przechwycone zapisać wyjaśnienie). W ten sposób zachowuję pełną elastyczność testowania - mogę uruchamiać pojedyncze testy bezpośrednio z wiersza poleceń, mogę tworzyć różnego rodzaju fantazyjne skrypty, jeśli chcę, mogę zmieniać ich kolejność według własnego uznania bez ponownej kompilacji itp.

Ale co ważniejsze, pozwala mi również na dołączanie testów napisanych w różnych językach lub przy użyciu różnych łańcuchów narzędzi w tym samym przebiegu. Na przykład testy jednostkowe, które piszę, są najprawdopodobniej w głównym języku projektu, a ich uruchomienie polega na zbudowaniu i wywołaniu plików binarnych; ale chcę również przetestować moją bazę danych i w tym celu może być konieczne podawanie skryptów SQL bezpośrednio do bazy danych; Mogę chcieć uruchomić narzędzie do analizy kodu statycznego na moim kodzie (nawet jeśli jest to po prostu jakiś linijka). Może chcę uruchomić mój statyczny kod HTML za pomocą narzędzia sprawdzania poprawności. Mógłbym uruchomić greppolecenie w bazie kodu, aby sprawdzić podejrzane konstrukcje, naruszenia stylu kodowania lub słowa kluczowe „czerwona flaga”. Możliwości są nieograniczone - jeśli można go uruchomić z wiersza poleceń i przestrzega „zero status wyjścia oznacza OK”, mogę go użyć.


Argument agnostyczny języka jest bardzo dobrym punktem, ponieważ planuję zaimplementować wiązania Pythona dla biblioteki na późniejszym etapie. Dzięki!
Benjamin Kloster

@tdammers: jakieś konkretne ramy testowania?
JBRWilkinson

@JBRWilkinson: tylko 30-liniowy skrypt powłoki. W przypadku większości używanych przeze mnie języków mam małe biblioteki do typowych zadań testowych, takich jak uruchamianie funkcji, porównywanie wyniku z oczekiwaną wartością i rzucanie, gdy się nie zgadzają. Ale dowolna struktura testów jednostkowych może być łatwo zintegrowana z takim „meta-systemem”, o ile może ona działać z wiersza poleceń i sygnalizować sukces / porażkę poprzez status wyjścia.
tdammers

2

Zwykle mam jedną bibliotekę do testów jednostkowych jednej aplikacji (lub pakietu bibliotek, który jest powszechnie udostępniany). W tej bibliotece próbuję replikować lub przybliżać przestrzenie nazw testowanych obiektów dla urządzeń testowych (głównie używam NUnit). Upraszcza to kompilację, ponieważ w .NET istnieje narzut związany z budowaniem każdego pliku binarnego, który wydłużyłby czas kompilacji rozwiązania z 20 projektami w porównaniu z rozwiązaniem z 10 projektami z tym samym LOC. Binaria testowe i tak nie są dystrybuowane, więc każda organizacja testów w binaria jest dla twojej wygody i ogólnie uważam, że YAGNI stosuje się tutaj jak wszędzie.

Teraz zwykle nie mam rozważań, które ma tdammers; mój kod jest praktycznie w całości w jednym języku, a jakikolwiek test obejmujący ciągi SQL nie jest testem jednostkowym (chyba że testujesz, czy producent zapytań zwraca oczekiwany ciąg SQL przy określonych kryteriach) i praktycznie nigdy nie testuję jednostkowo rzeczywistych Interfejs użytkownika (w wielu sytuacjach jest to po prostu niemożliwe). Korzystam również z biblioteki testów jednostkowych, która jest dobrze akceptowana przez narzędzia innych firm, takie jak boty kompilacyjne i wtyczki IDE, więc wszelkie obawy związane z uruchomieniem poszczególnych testów, częściowych pakietów itp. Są minimalne.


1
Chyba kwestia kultury - w środowisku .NET prawdopodobnie rozumowałbym podobnie jak ty.
tdammers
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.