Unit testy dla embeded

Jak podejść do tematu testów jednostkowych dla systemów wbudowanych

O przydatności Unit Testów (testów jednostkowych) nie trzeba się rozpisywać. Stanowią one wspaniały parasol ochronny dla dodawania nowego kodu i przeprowadzania refaktoru.

Możemy odważniej dodawać nowe funkcjonalności i śmielej dokonywać zmian w istniejącym kodzie jeśli mamy pewność, że obecne działania nie wpływają negatywnie na dotychczasowe dokonania.

Frameworków do tworzenia testów jednostkowych istnieje wiele (CppUnit, GTest, etc). Skupiając się na systemach wbudowanych interesować nas jednak będzie lekki framework działający w języku C.

Najprostsze środowowisko do tworzenia UT składa się z minimalistycznego frameworku MinUnit uzupełnionego o równie niewielki generator mocków FFF (Fake Function Framework).

Framework dostarcza zestawu assertów używanych do sprawdzenia czy test się powiódł oraz makr do grupowania testow. Generator mockow tworzy sztuczną metodę wywyoływaną z wnętrza testowanej funkcji zastępując oryginalne wywołanie.

Mock jest tworzony na podstawie definicji zawartej w pliku nagłówkowym testowanego modułu. Mock może:

  • zawierac w sobie licznik wywolan
  • przechwytywac argumenty z jakimi został wywołany
  • zwracac wymuszoną wartoś
  • wywyoływac przypisana do wskaznika funkcję

Oba narzędzia dostarczane są w postaci pojedynczych plików nagłókowych. Można je pobrac z githuba: Minunit oraz FFF

Środowisko testowe najlepiej skonfigurować jako nowy projekt w Eclipse, a testowane pliki źrodłowe i nagłówkowe (SUT - System Under Test) podlinkować poprzez wybór opcji w projekcie: New Folder -> Advanced -> Link to alternative location i podanie ścieżki do miejsca gdzie są testowane pliki źródłowe.

Należy pamiętać by pliki w których znajdują się mockowe funkcje wykłuczyć z budowania poprzez [ppm na pliku] -> Resource Configuration -> Exclude from build. Dzięki temu nie pojawią się błędy o istniejących duplikatach funkcji (FFF stworzy je za nas).

unit testy embeded - testy jednostkowe stm32

Powyższy screen przedstawia strukturę projektu. Jak widać pliki minunit.h i fff.h dołączamy do projektu, dla lepszej organizacji warto je umiescic w odrebnym folderze i wskazac ich położenie w ustawieniavch kompilatora (projekt -> Properties -> C/C++ build -> GCC C Compiler -> Includes -> Include Path).

Tworzymy plik z testami dotczacymi danego modulu. Na poczatku musi znalezc sie wywolanie makraDEFINE_FFF_GLOBALS, ktore tworzy inicjalizuje. Nastepnie dla kazdej funkcji, dla której chcemy stworzy mocka wywolujemy makro FAKE_VOID_FUNC([nazwa_funkcji]) . Tworzy ono falszyny obiekt do ktorego mozemy odwolac sie w testach:

Mock danej funkcji zostaje utworzony tylko w jednym egzemplarzu i istnieje globalnie, więc dla każdego nowego testu powienien zostac zresetowany poprzez wywolanie makra RESET_FAKE([nazwa_funkcji]. Dla kazdego mozliwego uzycia funkcji piszemy przypadek testowy. Przykładowa funckcja ktora chemy przetestowac:

Funkcja w zalezności od tego jaki argument zostal jej przekazany wywołuje jedną z dwóch funkcji pochodzących z innego modułu (uwaga, nie ma możliwości tworzenia mocków dla funkcji znajdujących się w tej samej jednostce kompilaji, tj. w tym samym pliku *.c).

Teraz czas na stworzenie grupy testów, tzw. test suit. Dodajemy naglowek "minunit.h" i tworzymy metody void test_setup() { } void test_teardown() { } zawierajace ewentualne akcje przygotowawcze wykonywane na starcie całejsuity testow oraz akcje konczace wykonywane po zakoczeniu wszystkich testow. Umieszczamy makro tworzącą zestaw testów MU_TEST_SUITE

Zawiera ona konfiguracje rozpoczecia i zakonczenia testow oraz kolejne testy do uruchomienia. Wykonywanie testów odbywa się przez skompilowanie i uruchomienie projektu.

Należy pamięta, że plik w którym znajdują się orginalne definicje mockowanych funkcji nie może zosta włączony do kompilacji (skutkowałoby to błędem "multiple definition".

Po zakonczeniu testów wyświetlany jest rezultat wskazujący ile testów było uruchomionych, ile umieszczono w nich asercji i ile z nich ewentualnie nie przeszło (wraz ze wskazaniem linijki kodu, która zawiniła).

Uruchamianie Unit Testów powinno być obowiązkowym punktem programu przed wrzuceniem kodu do repozytorium. Mozna zautomatyzowac ten proces tworząc odpowiedni skrypt w systemie łącznie z logowaniem informacji do pliku

TAGS: unit testy embeded, testy jednostkowe stm32 , minunit, FFF ,