najlepsza praktyka podczas testowania jednostkowego dla wbudowanego programowania

45

Szukam strategii najlepszych praktyk dla kodu testowania jednostkowego napisanego dla systemu wbudowanego. Przez system wbudowany rozumiem kod, taki jak sterowniki urządzeń, programy obsługi ISR ​​itp., Rzeczy, które są bardzo zbliżone do metalu.

Większość testów jednostkowych nie jest możliwa bez przetestowania na sprzęcie za pomocą ICE. Czasami wbudowana jednostka musi być również podłączona do innych bodźców, takich jak przełączniki mechaniczne, silniki krokowe i żarówki. Zwykle dzieje się to ręcznie, automatyzacja byłaby świetna, ale trudna i droga do osiągnięcia.

Aktualizacja

Natknąłem się na środowisko testowe C, które wydaje się całkiem skuteczne w testowaniu osadzonych projektów. Wykorzystuje pomysły kpienia ze sprzętu. Sprawdź Unity , CMock i ewentualnie Ceedling .

Aktualizacja 06 lipca2016

Wpadłem na cmockę - wydaje się, że bardziej aktywnie pracowałem.

tehnyit
źródło
1
W podobnych okolicznościach wybraliśmy się na Cmockę
Mawg
Napisałem bardzo dokładny samouczek na ten temat: Testowanie jednostkowe wbudowanych aplikacji C w Ceedling
Dmitry Frank

Odpowiedzi:

28

Oddalę się od zależności sprzętowych na jak najwcześniejszym etapie i zbuduję system na emulacjach oprogramowania / wiązkach testowych, umożliwiając wszelkiego rodzaju ramy testowe. Często mój komputer PC był używany do testowania aż 95% lub więcej całego systemu. Koszt dodatkowego obciążenia (kolejna warstwa abstrakcji) łatwo odzyskał czystszy kod wygenerowany w wyniku tej abstrakcji.

Testowanie naprawdę niemetalicznych części wbudowanego systemu jest zwykle oddzielną aplikacją (test jednostkowy?), Która hamuje oprogramowanie układowe znacznie wykraczając poza to, co aplikacje mogą nawet osiągnąć. Automatyzacji można dokonać - kosztem, ale nie jest to typowe.

Chyba że masz budżet na zbudowanie testowej wiązki sprzętowej, w tym pełnej wersji ICE. Jest to absolutnie w porządku, ponieważ ogólnie testy funkcjonalne są niewielkie.

mattnz
źródło
To w połączeniu z odpowiedzią Jonathana Cline ieee jest skuteczną strategią. Użyj abstrakcji, aby przetestować większość kodu, a używając prostego szkieletu testowego przetestuj nie dające się abstrakcyjnie bity na rzeczywistym sprzęcie. Osobiście widziałem tę pracę na wielu platformach.
Tim Williscroft
3
Każdy produkowany przez nas produkt ma warstwę abstrakcji sprzętu z implementacją sterowników dla platformy docelowej i komputera. To pozwala nam łatwo przeprowadzać testy jednostkowe. Inne zalety: możemy również przeprowadzać szybkie testy systemu i opracowywać większość oprogramowania bez sprzętu (ponieważ będzie on dostępny później).
MaR
15

Niezbędnym narzędziem do opracowania jest wtryskiwacz sygnału. System osadzony będzie miał pewien sposób na połączenie z systemem hosta (zazwyczaj za pośrednictwem portu szeregowego zarezerwowanego do debugowania). Skorzystaj z tego, aby wysłać dane testowe (najlepszą opcją jest sformatowanie zwięzłe ascii, aby ludzie mogli go łatwo symulować).

Całkowicie nie zgadzam się z tą częścią twojego pytania: „automatyzacja byłaby świetna, ale trudna i droga do osiągnięcia”.

Używając TeraTerm jako wtryskiwacza sygnału portu szeregowego i pisząc niektóre makra TeraTerm (zajmuje około 20 minut), istnieje ogromny zestaw zautomatyzowanych testów, które można przeprowadzić na dowolnej części wbudowanego systemu - niezależnie od tego, czy jest to warstwa sterownika, O / S, warstwa 4-5 itp. TeraTerm: http://en.sourceforge.jp/projects/ttssh2/

Jeśli port szeregowy nie jest dostępny w systemie wbudowanym, użyj narzędzia sprzętowego do konwersji danych portu USB / portu szeregowego na sygnały cyfrowe (również niedrogie i łatwe do osiągnięcia). Kiedy to czytasz, używam płytki mikrokontrolera o wartości 30 USD (UBW: http://www.schmalzhaus.com/UBW32/ ) do testowania wbudowanego systemu do produkcji, poprzez wstrzykiwanie bodźców za pomocą makr TeraTerm, które są wysyłane przez USB / szeregowy do mikrokontroler, na którym działa zmodyfikowane oprogramowanie układowe, które wykonuje wejścia cyfrowe i monitoruje wyjścia cyfrowe docelowego systemu wbudowanego. W połączeniu z tym opracowaliśmy skrypt Pythona (używa pyserial i pexpect) do automatyzacji wstrzykiwania danych i sprawdzania poprawności danych. Żaden z nich nie jest trudny i żaden z nich nie jest drogi. Z mojego doświadczenia wynika, że ​​menedżerowie wydają duże pieniądze (takie jak sprzęt testowy o wartości 30 000 USD), gdy zespół testowy jest niedoświadczony i nie jest w stanie wymyślić tych łatwych rozwiązań - niestety, sprzęt wielkoformatowy ogólnego przeznaczenia często nie obejmuje przypadków testowych które wychwytują najgorszy przypadek / etc systemu docelowego. Tak więc niedroga metoda jest lepsza do pokrycia testowego. Uwierz lub nie.

Jonathan Cline IEEE
źródło
1
Cóż, złożyłem drogie oświadczenie, pracując w branży motoryzacyjnej i wszystko musi być deterministyczne, powtarzalne i zwykle wymaga rozwoju kilku inżynierów. Również w przypadku użycia większej liczby elementów w łańcuchu testowym problemem staje się konserwacja. Dziękujemy za poinformowanie nas o UBW, wygląda to na dobrą opcję.
tehnyit
2
Tylko nie zaczynaj mnie od pracy w LabView ... to zwykle okropne rzeczy.
Jonathan Cline IEEE
1
Nasi inżynierowie testowi uwielbiają LabView, sam nie do końca to rozumiem.
tehnyit
Jest to dość zbliżone do tego, co robię dla różnych testów, tylko używam Pythona i ich bibliotek szeregowych. Mógłbym wtedy podłączyć moje testy niskiego poziomu do testerów jednostek Pythona wraz z czymś takim jak Flask / Qt, aby dać łatwą w użyciu nakładkę.
radix07,
5

To bardzo trudny problem.

W rzeczywistości zaprojektowałem uprząż testującą jednostkę dla systemu osadzonego, która umożliwiałaby symulację zdarzeń / przerwań sprzętowych i kontrolowała czas wykonania (aby upewnić się, że pokrywamy wszystkie możliwe przeplatania z powodu współbieżności), i zajęło to zespołowi programiści od ponad 2 lat wdrażają go i wprowadzają w życie. Ten projekt jest zastrzeżony, ale podobny (prostszy w projektowaniu) projekt jest dostępny tutaj .

Tak, automatyzacja byłaby świetna. Tak, osiągnięcie tego jest bardzo trudne i kosztowne. Tak, czasami trzeba to zrobić. Rzadko jednak z mojego doświadczenia wynika, że ​​w większości przypadków szybsze i tańsze jest używanie silników krokowych i żarówek i sprawienie, aby wszystko działało ręcznie.

littleadv
źródło
Odkryłem, że jednostka, którą ręcznie wykonuje, jest podatna na błędy, zwykle albo w generowaniu bodźca, albo w mierzeniu wyników. Szczególnie prawdziwe, jeśli test jednostkowy jest skomplikowany. Jeśli musisz ponownie wykonać test jednostkowy, staje się on jeszcze bardziej podatny na błędy.
tehnyit
@tehnyit - tak, dlatego postanowiliśmy opracować system automatyki. Czasami rzeczy nie można w ogóle zrobić ręcznie, ale test jednostkowy musi być kompleksowy i obejmować problemy z harmonogramem. Zatem nie masz dużego wyboru, ale automatyzacja na tym poziomie jest bardzo kosztowna.
littleadv
4

Edycja: moja odpowiedź jest zbliżona do Mattnza, myślę ...


Chcę powiązać ten problem z innymi, wszystkimi testami, które zależą od czegoś zewnętrznego w stosunku do twojego kodu (np. Zegara systemowego, trwałego systemu plików lub bazy danych, kontaktu z zewnętrzną usługą internetową ...). Sugeruję taką samą politykę dla wszystkich, izoluj dwa poziomy w dwóch warstwach kodu.

Testowanie pojedynczej operacji zewnętrznej

Możesz fizycznie przetestować każdą operację. Sprawdź, czy zegar systemowy podaje prawidłowy czas, sprawdź, czy plik rzeczywiście pamięta, co zostało zapisane, sprawdź, czy urządzenie odbiera jedną operację ...

Te testy:

  • powinno być tak proste, jak to możliwe: żaden algorytm, żaden warunek ani pętla
  • może być zależne od zamówienia i maszyny: więc musisz przestrzegać ścisłej kolejności i powtarzać na każdym sprzęcie
  • są w większości stabilne w trakcie projektu, więc nie musisz ich tak często uruchamiać
  • więc uruchomienie ich ręcznie jest opcją; automatyzacja jest jeszcze lepsza, jeśli nie nadmiernie złożona
  • Pamiętaj, że to , co jest testowane, nie jest twoim kodem , jest to narzędzie, którego potrzebuje Twój kod ... Więc testowanie może być dla Ciebie opcjonalne, mogło być zrobione przez inny zespół ...

Testowanie logiki (kodu, algorytmu), która łączy operacje zewnętrzne

Mając warstwę kodu do wykonywania rzeczywistych operacji zewnętrznych, ukrywając je za interfejsem, który można łatwo wyśmiewać, logika nie jest już zależna od rzeczywistych urządzeń fizycznych ...

Możesz po prostu przetestować, jak w każdym zwykłym projekcie, nie ma już wbudowanego trudnego do przetestowania kodu .

KLE
źródło
3

Wbudowane symulatory procesorów można ogólnie zaprogramować tak, aby symulowały również sprzęt. Robią to wszystkie technologie wirtualizacji inne niż Xen. Ale musisz napisać kod, który udaje, że ma jakieś rejestry pod jakimś fizycznym adresem lub, na x86, adresem na szynie I / O, a następnie musisz odpowiadać na odczyty i zapisy na te adresy, jakby twoje oprogramowanie było fizycznym chip, do którego uzyskiwano dostęp do rejestrów kontroli i statusu.

Jeśli chcesz to zrobić, proponuję zmodyfikować QEMU. Ale to nie będzie łatwe. Tego rodzaju czynności są zazwyczaj wykonywane tylko wtedy, gdy projektujesz niestandardowy układ z mikrokontrolerem i innymi rdzeniami dla swoich I / O.

System rozwoju sprzedawany przez ARM Holdings zapewnia taką możliwość i jest prawdopodobnie łatwiejszy w obsłudze niż hakowanie na QEMU, ale jest bardzo drogi.

Istnieje kilka emulatorów ARM typu Open Source, które uruchamiają jeden podprogram, który sam może wywoływać inne podprogramy, których można użyć do debugowania dostrajania wydajności podprogramów, które nie zależą od dostępu sprzętowego. Wykorzystałem jeden z nich, aby odnieść sukces w optymalizacji szyfrowania AES dla ARM7TDMI.

Możesz napisać prostą wiązkę testową w C lub C ++, połączyć z nią testowaną klasę lub podprogram, a następnie uruchomić go w symulatorze.

Przez lata zastanawiałem się nad podobnym problemem, jak testować jednostkowo kod jądra systemu Linux lub Mac OS X. Powinno być możliwe, ale tak naprawdę nigdy nie próbowałem. Jednym z możliwych jest zbudowanie pełnego jądra, zamiast testowania kodu w izolacji, z ramami testów jednostkowych podłączonymi bezpośrednio do jądra. Następnie uruchomiłbyś testy jednostkowe z jakiegoś zewnętrznego interfejsu.

Być może bardziej produktywne byłoby skorzystanie z narzędzia do pokrywania kodu, a następnie przetestowanie oprogramowania wewnętrznego jako kompletnego pakietu za pomocą zewnętrznego interfejsu. Narzędzie pokrycia znajdzie ścieżki kodu, które nie zostały jeszcze przetestowane, więc możesz dodać dodatkowe testy zewnętrzne, aby uzyskać większy zasięg.

Mike Crawford
źródło
3

Podobnie jak w przypadku niewbudowanych TDD, pozorowane obiekty są zdecydowanie twoim przyjacielem.

Utrzymuj interfejs do podstawowego sprzętu w czystości i prostocie, aby wszystko, co znajduje się powyżej najniższego poziomu, mogło zostać wykpione i będziesz miał o wiele łatwiejszy czas - jeśli projektujesz aplikację osadzoną z myślą o testowaniu, testowanie zawsze będzie przebiegało płynniej .

Również fakt, że możesz nie być w stanie przetestować on-line do późnej fazy projektu, nie oznacza, że ​​nie powinieneś przygotowywać zestawu testów on-line.

Powinny one (początkowo) tylko przetestować bity, których nie można przetestować offline. Jasne, to nie TDD (ponieważ tworzysz testy z wyprzedzeniem), ale twoja wersja offline TDD powinna dać ci dobre wyobrażenie o tym, jak powinien wyglądać twój interfejs sprzętowy, a tym samym jakie testy online musisz wykonać.

Ponadto, jeśli programowanie online kosztuje znacznie więcej niż programowanie offline (tak jak tam, gdzie pracuję), może zaoszczędzić wiele czasu w Internecie dzięki dobrze zrozumiałemu zestawowi testów.

Mark Booth
źródło
+1 za wprowadzenie fałszywych obiektów na talerz, @mark. Jedynym problemem jest to, że zapewnienie dokładności próbnych obiektów, co oznacza, że ​​zrozumienie obiektu, który ma być wyśmiewany, powinno być dość głębokie. Jest to dobre, ponieważ zmusza programistę do zrozumienia zachowania zewnętrznych obiektów, z którymi się łączy.
tehnyit
1

W programowaniu wbudowanym często wykonujesz skanowanie granic, aby zweryfikować działanie całej aplikacji (w tym sprzętu). Zobacz także JTAG do debugowania systemu.

Testowanie procedur czystego oprogramowania bez połączenia ze sprzętem może być wykonywane przez standardową platformę C Unit Test, taką jak Check . Uważaj jednak na ograniczenia pamięci (zwłaszcza na stosie itp. Na małych urządzeniach). Poznaj swoje umowy! Możesz także spróbować wyodrębnić procedury oprogramowania ze sprzętu, aby uzyskać większy zasięg testowy, ale zwykle jest to kosztowne pod względem wydajności na urządzeniach wbudowanych, takich jak małe PIC lub AVR. Można jednak kpić z portów sprzętowych, aby uzyskać większy zasięg (i oczywiście można również przetestować tę próbę).

Możesz także spróbować użyć emulatorów do symulatorów układów lub obwodów, ale tego rodzaju narzędzia są drogie (zwłaszcza w połączeniu) i skomplikowane.

Sokół
źródło
Zgadzam się ze skanowaniem granic i JTAG, ale ze względu na konstrukcję sprzętu nie zawsze jest to możliwe lub dostępne.
tehnyit