Elektroda.pl
Elektroda.pl
X

Wyszukiwarki naszych partnerów

Wyszukaj w ofercie 200 tys. produktów TME
Kategoria: Kamery IP / Alarmy / Automatyka Bram
Montersi
Proszę, dodaj wyjątek elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

uTest - framework C++ do testów jednostkowych dla urządzeń wbudowanych

tymon_x 05 Lut 2017 22:27 1395 7
  • #1 05 Lut 2017 22:27
    tymon_x
    Poziom 30  

    1. Wstęp

    Testy jednostkowe odgrywają ważna rolę w procesie wytwarzania kodu źródłowego. W połączeniu z metodyką test-driven development (TDD) tworzy nad wyraz potężne narzędzie. Szybsze wykrywanie potencjalnych błędów, dążenie do izolowania i uproszczenia metod, dokumentowania kodu poprzez testowanie i wiele innych czynników, które sprawiają że projekt nabiera nowej jakości: Co to są testy i po co są testy jednostkowe?

    2. Kolejny nudny framework...

    µTest

    Stworzony w wolnych chwilach, w celach hobbystycznych. Po co nam kolejny framework do testów jednostkowych jak ich tyle na rynku? Przed stworzeniem µTest'a, przetestowałem kilka mniej lub bardziej poważnych projektów, szczególnie interesowało mnie natywne uruchomienie testów na mikrokontrolerach z jakimś rdzeniem Cortex-Mx. Na pierwszy strzał poszedł popularny Google Test , trochę dłubania i typowego hackowania, udało się wygenerować prosty działający test. Mankamentem był rozmiar wynikowy powyżej 100kB. Troszkę to dużo :)
    Najbardziej obiecujący wydawał się dla mnie Cmocka i Unity . Z pierwszym prosty test wyniósł jakieś 28kB. Drugi jakieś 16kB. Wszystko na -Os i włączonym semistoning'iem. Był tylko jeden problem... zostały napisane w C :D Ręczna rejestracja testów, brak silnego typowania, dziwne makra... Ale także utrudniona zmiana formatu wyjściowego (json, html itp.) czy strumienia wyjściowego. I tak o to powstał µTest, napisane w całości w C++11, wykorzystujący wiele dobrodziejstw tego języka w tym moje ulubione SFINAE :) I przynajmniej globalna przestrzeń nazw jest uboższa o brak dziwnych makr (max i itp). Z prostym testem udało się zejść do 13kB i to jest potęga C++ :) Można i zejść poniżej 9kB wykorzystując bezpośrednie wysłanie na przykład przez UART zamiast semihosting (fwrite) oraz LTO.

    3. Współpraca

    I to jest gwóźdź punkt programu. Chciałbym wymienić się opiniami i doświadczeniem z osobami, które mają styczność z testowaniem jednostkowym i TDD. Ale także zachęcić nowe osoby to spróbowania tego stylu programowania w systemach wbudowanych. Dlatego zachęcam do korzystania (w końcu na super licencji 3-BSD), chciałbym poznać wasze (mam nadzieję krytyczne) uwagi, ale także propozycje jakich funkcjonalności wam brakuje w takich framework'ach. Jest jeszcze wiele rzeczy do zrobienia, więc zakładka Issues na repozytorium czeka na wypełnienie :)

  • Pomocny post
    #3 05 Lut 2017 23:01
    Freddie Chopin
    Specjalista - Mikrokontrolery

    Swego czasu - gdy rozważałem w którą stronę podążyć z testami mojego RTOSa - stwierdziłem, że bardziej praktyczne niż testy jednostkowe są testy funkcjonalne. Powodów jest kilka:
    1. testy jednostkowe są ciężkie do zrobienia dla prywatnych funkcji lub bardziej "wewnętrznych" części danego projektu - bez cudów typu "#define private public" czy robienia tysięcy mocków się raczej nie obejdzie,
    2. trudno przetestować cokolwiek co ma jakiś stan, a akurat w RTOSie to stan jest bardziej istotny niż jednostkowe zachowania,
    3. w zasadzie to samo co powyżej w przypadku gdy scenariusze testowe są bardziej rozbudowane (typu badanie zależności działania kilku wątków na raz),

    Pewnie idealny przypadek to testy jednostkowe do rzeczy które łatwo wyizolować + testy funkcjonalne do rzeczy ze stanem i bardziej rozbudowanych. Ale to trochę za dużo szczęścia dla małych projektów (; TDD jest generalnie fajne, ale jeśli ograniczysz się do testów jednostkowych, to dla takowych w projekcie embedded widzę dosyć ograniczone zastosowanie.

    Niemniej jednak - za C++ wielki plus (; za przyznanie się, że SFINAE to Twój ulubiony feature tego języka - wielki minus <:

    Dodano po 3 [minuty]:

    grko napisał:
    Znajomi od C++ używają:
    https://github.com/philsquared/Catch

    ale nie wiem czy nadaje się to do embedded.

    Nazwa sugeruje użycie wyjątków C++ i tak jest w rzeczywistości - choćby tu: https://github.com/philsquared/Catch/blob/master/single_include/catch.hpp#L2324

  • #4 05 Lut 2017 23:10
    tymon_x
    Poziom 30  

    grko napisał:
    Znajomi od C++ używają:
    https://github.com/philsquared/Catch

    ale nie wiem czy nadaje się to do embedded.

    Pierwsza próba kompilacji za pomocą arm-none-eabi skończyła się błędem z powodu braku rzeczy związanych z OS (w tym przypadku Linux). Ten wątek na github'ie Catch'a target embedded devices? prowadzi do jego lżejszej wersji, której nie sprawdzałem. Pewnie wymagałoby to więcej hackowania niż przy Google Test...

    Freddie Chopin napisał:
    Niemniej jednak - za C++ wielki plus (; za przyznanie się, że SFINAE to Twój ulubiony feature tego języka - wielki minus <:

    Czyli wychodzi na zero :) Większość rzeczy z <type_traits> w tym std::enable_if jest bardzo przydatna, żeby zmusić kompilator do wyboru odpowiedniej metody bez generowania tysiąca wersji tego samego lub nakierowania go na odpowiednią wersję przeciążonej metody. Dla mnie super :)

    Freddie Chopin napisał:
    1. testy jednostkowe są ciężkie do zrobienia dla prywatnych funkcji lub bardziej "wewnętrznych" części danego projektu - bez cudów typu "#define private public" czy robienia tysięcy mocków się raczej nie obejdzie,

    Zawsze można podmienić implementację i zostawić interfejs jaki jest z nagłówka. Wystarczyłoby dodać tylko inne reguły do kompilacji, żeby tylko część rzeczy udawało tą "prawdziwą bibliotekę" per test jednostkowy.

  • #5 05 Lut 2017 23:15
    Freddie Chopin
    Specjalista - Mikrokontrolery

    tymon_x napisał:
    Czyli wychodzi na zero Większość rzeczy z <type_traits> w tym std::enable_if jest bardzo przydatna, żeby zmusić kompilator do wyboru odpowiedniej metody bez generowania tysiąca wersji tego samego lub nakierowania go na odpowiednią wersję przeciążonej metody. Dla mnie super

    SFINAE jest potężne, ale jeszcze bardziej potężne to są błędy jakie wypluwa kompilator jak coś mu się nie podoba (; Szczególnie te które zajmują 50 ekranów <: Ale tak serio, to też czasem używam [;

  • #6 05 Lut 2017 23:31
    tymon_x
    Poziom 30  

    Freddie Chopin napisał:
    SFINAE jest potężne, ale jeszcze bardziej potężne to są błędy jakie wypluwa kompilator jak coś mu się nie podoba (; Szczególnie te które zajmują 50 ekranów <: Ale tak serio, to też czasem używam [;

    Clang ma w miarę czytelne komunikaty, przynajmniej wymusił na deweloperów od GCC kolorowanie wyjścia z błędami :) Później chcę dodać skrypt CMake do budowania pod Cortex za pomocą clang , co ciekawe kompilacja za pomocą starszej wersji daje czasem trochę optymalniejszy (czytaj trochę mniejszy kod) niż w najnowszym GCC :P Ale fakt że SFINAE potrafi czasem dać w kość, ale jak się w miarę sensownie, a przede wszystkich rozważnie użyje niektórych szablonów, to efekt końcowy zostaje wynagrodzony. Chociaż sam nie wiem czy wszystkie metody z µTest zadziałają w każdym przypadku... z czasem to wyjdzie :)

  • #7 06 Lut 2017 08:23
    Freddie Chopin
    Specjalista - Mikrokontrolery

    tymon_x napisał:
    Później chcę dodać skrypt CMake do budowania pod Cortex za pomocą clang

    Tak swoją drogą to jakie zalety ma używanie LLVM/Clang dla takich mikrokontrolerów zamiast czystego GCC? To jest pytanie bez podtekstów (;

  • #8 06 Lut 2017 09:24
    tymon_x
    Poziom 30  

    Freddie Chopin napisał:
    Tak swoją drogą to jakie zalety ma używanie LLVM/Clang dla takich mikrokontrolerów zamiast czystego GCC? To jest pytanie bez podtekstów (;

    To już subiektywna preferencja, który kompilator wybrać. W zależności od projektu, czasem Clang generuje mniejszy i szybszy kod niż GCC, a czasami jest wręcz odwrotnie. Osobiście kompiluje projekty korzystając z obydwu, µTest jest teraz kompilowany przez travis w ramach CI pod GCC i Clang (x86). Z osobistych doświadczań, to Clang kompiluje kod trochę szybciej, ma inne ostrzeżenia, gdzie zawsze używam generycznej flagi -Weverything, komunikaty z kompilatora są dla mniej bardziej oczywiste niż z GCC, chociaż ten ostatni pod presją projektu LLVM dużo się poprawił pod tym względem. Clang/LLVM bardziej nadąża z standardami do C++ niż GCC. W dodatku w ramach LLVM/Clang są dostępne dodatkowe narzędzia, m.i. plugin do auto uzupełniania kodu YouCompleteMe dla VIM'a, który korzysta z Clang, narzędzia do statycznej analizy kodu (clang-analyzer) czy do zautomatyzowanego formatowania kodu.

    Update:
    Można wygenerować report z pokrycia kodu dla Cortex-Mx. Wystarczy mieć zainstalowane QEMU i LCOV, arm-none-eabi-gcov poradzi sobie z resztą. Kod kompilujemy za pomocą flag -O0 -g --coverage, to załatwi sprawę. Przykład: Build and run tests with code coverage results

 Szukaj w ofercie
Zamknij 
Wyszukaj w ofercie 200 tys. produktów TME