piątek, 14 grudnia 2018

[3] Unit test - C Unit Test - implementacja testów w Eclipse

W tym poście chciałbym opisać sposób implementacji C Unit Test z przykładem na mikrokontrolery STM32 w środowisku System Workbench.

[Źródło: http://academy.trendonix.com]

Opis:


C Unit Test jest to prosty system testów jednostkowych przystosowanych dla aplikacji napisanych w języku C. Przykładowy projekt można pobrać z SourceForge. Jego zaletami są na pewno niewielkie rozmiary oraz prostota obsługi środowiska. Jednak należy pamiętać, że proces obsługi błędów oraz możliwości jakie program daje użytkownikowi będą mniejszy niż przy innych bardziej popularnych rozwiązaniach (jak np. CppUnitTest).

Przygotowanie projektu:


Po pobraniu projektu należy go rozpakować, usunąć zbędne elementy po czym dodać go do Eclipsa jako "C/C++ -> Makefile Project with Existing Code". Tam dodajemy projekt z przygotowanych źródeł.

Najważniejszym elementem jaki musimy przygotować to plik Makefile. Powinien on się prezentować następująco:

  1. cutgen: cutgen.c
  2.     gcc -D__LINUX__ cutgen.c -o cutgen
  3. check: cutgen cutcheck.c
  4.     gcc cutcheck.c CUT_UnitTest.o -o cutcheck
  5.     ./cutcheck
  6. cutcheck.c: CUT_UnitTest.o
  7.     ./cutgen CUT_UnitTest.c -o cutcheck.c
  8. CUT_UnitTest.o: CUT_UnitTest.c
  9.     gcc -c CUT_UnitTest.c
  10. clean:
  11.     rm -*.o *~ cutcheck* cutgen
  12.    
  13. all: check

Po udanej kompilacji należy dodać nazwę pliku skompilowanego (*.o) do pliku Makefile. Wtedy struktura tego pliku będzie wyglądała następująco:

  1. cutgen: cutgen.c
  2.     gcc -D__LINUX__ cutgen.c -o cutgen
  3. check: cutgen cutcheck.c CUT_UnitTest.o
  4.     gcc cutcheck.c CUT_UnitTest.o -o cutcheck
  5.     ./cutcheck
  6. cutcheck.c: CUT_UnitTest.o
  7.     ./cutgen CUT_UnitTest.c -o cutcheck.c
  8. CUT_UnitTest.o: CUT_UnitTest.c
  9.     gcc -c CUT_UnitTest.c
  10. clean:
  11.     rm -*.o *~ cutcheck* cutgen
  12.    
  13. all: check

Funkcje testowane dodajemy albo w pliku / projekcie w którym wykonujemy testy, bądź co jest lepszym rozwiązaniem w projekcie docelowym.

Dodanie informacji o zewnętrznych projektach ustawia się przez dodanie referencji oraz wprowenia katalogów inc oraz src w zakładce "Path and Include". Po dodaniu informacji poszczególne pliki dołączamy do pliku testowego w następujący sposób:

  1. #include "../TestProject/src/test123.c"
  2. #include "../TestProject/inc/test123.h"

Aby dołożyć kolejne pliki do testowania to należy zmodyfikować plik Makefile, tak aby wiedział on o istniejącym drugim pliku testowym. Wykonuje się go w następujący sposób.

  1. cutgen: cutgen.c
  2.     gcc -D__LINUX__ cutgen.c -o cutgen
  3. check: cutgen cutcheck.c
  4.     gcc cutcheck.c CUT_UnitTest.o CUT_UnitTest2.o -o cutcheck
  5.     ./cutcheck
  6. cutcheck.c: CUT_UnitTest.o CUT_UnitTest2.o
  7.     ./cutgen CUT_UnitTest.c CUT_UnitTest2.c -o cutcheck.c
  8. CUT_UnitTest.o: CUT_UnitTest.c
  9.     gcc -c CUT_UnitTest.c
  10. CUT_UnitTest2.o: CUT_UnitTest2.c
  11.     gcc -c CUT_UnitTest2.c
  12. clean:
  13.     rm -*.o *~ cutcheck* cutgen
  14.    
  15. all: check

Przykładowe testy:


Testy projektu przeprowadzimy na kilku prostych funkcjach zewnętrznych.

Operacje testowe wykonuje się na kilku makrach, zdefiniowanych w opcji cut.h:

ASSERT:

Standardowa komenda sprawdzania zadanego warunku wraz z przesłaniem zadanej informacji na ekran:

  1. ASSERT(valueSum == 5, "addSmallNum Function Error");
  2. ASSERT(valueSum < 5, "addSmallNum Function Error");

Można też do makra assert podać bezpośrednio funkcję wykonującą obliczenia czy porównania i zwracając odpowiedni wynik operacji. Należy przy tym pamiętać, że błąd zostanie wyświetlony tylko gdy wynikiem działania takiej funkcji będzie wartość 0.

  1. ASSERT(compareValues(2,3), "addSmallNum Function Error");


ASSERT_EQUALS:

Działa podobnie jak ASSERT, z tą różnicą, że tutaj możliwe jest tylko porównywanie dwóch wartości czy są sobie równe. W przypadku błędu zostanie wyświetlony zdefiniowany komunikat:

  1. ASSERT_EQUALS(valueSum, 5, "Sum operation error");

To są właściwie dwie podstawowe makra jakie można wykorzystać do tworzenia testów jednostkowych.

Przykładowe, krótkie, procedury testowe są dostępne w przykładach umieszczonych w pliku .zip umieszczonych na stronie SourceForge oraz w plikach udostępnionych przeze mnie na dysku Google.

Gdy już dodamy testy do poszczególnych plików to są one automatycznie po kompilacji dodawane do wykonania w funkcji main znajdującej się w pliku cutcheck:

  1. extern void __CUT_BRINGUP__Pass( void );
  2. extern void __CUT_TAKEDOWN__Pass( void );
  3. extern void __CUT__addSmallNum_Test1( void );
  4. extern void __CUT__SimpleAssertTest( void );
  5. extern void __CUT__TestB( void );
  6. extern void __CUT__TestC( void );
  7. extern void __CUT_BRINGUP__Pass_2( void );
  8. extern void __CUT_TAKEDOWN__Pass_2( void );
  9. extern void __CUT__addBiggerNumTest( void );
  10. int main( int argc, char *argv[] )
  11. {
  12.   if ( argc == 1 ) { cut_init( -1 ); }
  13.   else { cut_init( atoi( argv[1] ) ); }
  14.   cut_start( "group-Pass", __CUT_TAKEDOWN__Pass );
  15.   __CUT_BRINGUP__Pass();
  16.   cut_check_errors();
  17.   cut_end( "group-Pass" );
  18.   __CUT_TAKEDOWN__Pass();
  19.   cut_start( "addSmallNum_Test1", 0 );
  20.   __CUT__addSmallNum_Test1();
  21.   cut_end( "addSmallNum_Test1" );
  22.   cut_start( "SimpleAssertTest", 0 );
  23.   __CUT__SimpleAssertTest();
  24.   cut_end( "SimpleAssertTest" );
  25.   cut_start( "TestB", 0 );
  26.   __CUT__TestB();
  27.   cut_end( "TestB" );
  28.   cut_start( "TestC", 0 );
  29.   __CUT__TestC();
  30.   cut_end( "TestC" );
  31.   cut_start( "group-Pass_2", __CUT_TAKEDOWN__Pass_2 );
  32.   __CUT_BRINGUP__Pass_2();
  33.   cut_check_errors();
  34.   cut_end( "group-Pass_2" );
  35.   __CUT_TAKEDOWN__Pass_2();
  36.   cut_start( "addBiggerNumTest", 0 );
  37.   __CUT__addBiggerNumTest();
  38.   cut_end( "addBiggerNumTest" );
  39.   cut_break_formatting();
  40.   printf("Done.");
  41.   return 0;
  42. }

W przypadku błędu w eclipsie zostanie wyświetlona następująca informacja:


Przy poprawnie wykonanych testach w oknie Konsoli wyświetli się następująca informacja:


Projekt opisany w tym poście jest do pobrania z dysku Google pod tym linkiem.