Ostatnio trochę eksperymentowałem z nowym frameworkiem do unit testów – Catch2. Główną różnicą od innych frameworków takich jak CppUTest czy GoogleTest jest rezygnacja z grup testowych na rzecz struktury Given-When-Then wspierającej Behavior Driven Design (BDD). Inną ważną zaletą jest fakt, że cały framework mieści się w jednym headerze, dlatego nie ma problemów z jego integracją.
Continue readingKategoria: Unit testy
Piramida testów – do czego służą poszczególne poziomy
W tym artykule odpowiemy sobie na pytanie jakie rodzaje testów powinniśmy wykonywać i w jakich proporcjach. Pomoże nam w tym piramida testów, czyli prosta graficzna reprezentacja ilości testów, kosztu ich utrzymania i szybkości wykonywania. Opiszemy również podstawowe cechy testów każdego poziomu i ich ograniczenia. Wbrew pozorom nie jest to tylko wiedza dla testerów, ale również dla developerów. Szczególnie jeśli korzystają z Test Driven Development.
Unit testy funkcji statycznych w C
W idealnym świecie nie testujemy szczegółów implementacyjnych jakimi są funkcje statyczne. To samo tyczy się prywatnych pól i metod klasy w językach obiektowych. Zamiast tego piszemy testy dla publicznego API i z pomocą odpowiednich mocków jesteśmy w stanie zaobserwować całe zachowanie testowanego modułu z zewnątrz. Rzeczywistość często nie jest taka różowa i musimy często jakoś dostać się do tego ukrytego kodu.
Jak testować nieskończone pętle?
Częstą wymówką, aby nie pisać unit testów jest „Tego kodu nie da się przetestować.”, otóż zwykle jednak się da, tylko trzeba chwilę pomyśleć jak się do tego zabrać. Jednym z takich trudniejszych przypadków jest testowanie nieskończonych pętli. W tym wpisie pokażę kilka technik służących do pokrycia ich unit testami.
Miary jakości unit testów
Pisząc unit testy chcielibyśmy wiedzieć, czy robimy to wystarczająco dobrze i czy dodajemy w ten sposób wartość do projektu. Informacja ta jest potrzebna programistom, aby mogli doskonalić swój warsztat i ułatwiać pracę zespołowi. Korzystają z niej również managerowie planując zadania, skład zespołu itp. Najczęściej wykorzystywaną metryką jest tutaj test coverage, jednak niesie ona jedynie ograniczoną informację. Ważne są również miary empiryczne, które ciężko przedstawić w formie liczbowej.
Pisanie własnych mocków
Nieodłącznym elementem TDD i unit testów jest mockowanie zależności. Powstało w tym celu sporo bibliotek dla różnych języków i różnych frameworków testowych. Mogłoby się więc wydawać, że wystarczy wybrać swoją ulubioną bibliotekę do mocków i po prostu jej używać. Okazuje się jednak, że pisanie prostych mocków samemu czasem może okazać się lepszym wyborem. Pokażę dzisiaj jak łatwo można napisać własne mocki do frameworków Unity i CppUTest.
Unity – framework testowy w C
Aby móc testować aplikacje embedded na platformie docelowej często potrzebujemy frameworka napisanego w czystym C. Najlepiej jeszcze, aby zajmował mało miejsca w pamięci i był jak najprostszy, aby dawał się skompilować na kompilatorach bez zaawansowanych opcji i funkcji bibliotecznych. Wymagania te spełnia framework Unity. Niestety nazwa jest dosyć niefortunna, pokrywa się z Unity do tworzenia gier i ciężko np. wyszukiwać teksty o frameworku w google.
CppUTest – framework do unit testów systemów embedded
Aby stosować Test Driven Development potrzebujemy odpowiedniego frameworka testowego implementującego obsługę scenariuszy i grup testowych, drukowanie outputu, czy asserty. Mimo iż brak takiego frameworka nie może być wymówką, aby nie testować (najmniejszy framework w C składa się z 3 linii kodu!), dobre narzędzie ułatwi nam pracę i zwiększy produktywność. Dzisiaj opiszę dość ciekawe podejście do testowania projektu napisanego w C – wykorzystanie frameworka w C++. A jest nim CppUTest.
TDD embedded – system buildowania
Podstawą TDD jest szybki feedback jaki otrzymujemy z unit testów. Oznacza to, że kompilacja i uruchomienie testów powinno trwać kilka sekund. Kluczem do osiągnięcia tak krótkiego czasu jest odpowiednio skonfigurowany system buildowania. Wiadomo, że w te kilka sekund nie uda nam się zbudować od zera całego projektu. System buildowania musi więc udostępniać nam odpowiednie opcje. W tym wpisie postaram się je przybliżyć. Będę pisał z punktu widzenia systemów embedded, ale część uwag spokojnie można odnieść do zwykłych aplikacji.
Proces TDD dla systemów embedded
Aby mikrocykl TDD Red-Green-Refactor był efektywny, kompilacja i wykonanie testu powinny trwać kilka sekund. W praktyce oznacza to, że testy nie są wykonywane na docelowej platformie i należy podjąć dodatkowe kroki w celu wykrycia ewentualnych problemów związanych ze sprzętem. W poprzednim wpisie wytłumaczyłem jak może w tym pomóc dual targeting. Dzisiaj opiszę jak powinien wyglądać proces tworzenia oprogramowania, aby minimalizować ryzyko związane ze sprzętem. Proces ten jako pierwszy opisał James Grenning (prowadzi świetnego bloga o TDD Embedded – link) w swojej książce „Test Driven Development for Embedded C”. Zaproponował on Embedded TDD Cycle składający się z pięciu kroków.