Ten post chciałbym poświęcić na opisanie dostępnych Asercji w CPPUnit wraz z sposobami ich testowania.
[Źródło: http://academy.trendonix.com]
Poniższe przykłady opiszę na jakichś przykładowych funkcjach.
CPPUNIT_ASSERT
Podstawowy sposób testowania. Sprawdza tyczy dany warunek jest prawdziwy.
Funkcja testowa wygląda następująco:
- bool checkCondition(uint8_t val1, uint8_t val2)
- {
- if(val1 < val2 || val1 == val2)
- {
- return true;
- }
- return false;
- }
I przykładowy test z użyciem wspomnianej asercji:
- void UnitTest::checkCondition_ValueOneSmallerThenValueTwo_ReturnTrue()
- {
- uint8_t value1ToPass = 23;
- uint8_t value2ToPass = 45;
- CPPUNIT_ASSERT(checkCondition(value1ToPass, value2ToPass));
- }
Ten warunek będzie działał także dla porównywania dwóch wartości w warunku. Funkcja testowa:
- int add(int a, int b)
- {
- return a + b;
- }
Instrukcja zadziała poprawnie tylko gdy dwie podane wartości będą sobie równe:
- void UnitTest::add_CheckIfSumIsOK()
- {
- int a = 5;
- int b = 4;
- int expectedValue = (a + b);
- CPPUNIT_ASSERT(add(a, b) == expectedValue);
- }
Do instrukcji możemy wprowadzić wszystkie warunki jaki by można było wstawić np. do instrukcji warunkowej If.
CPPUNIT_ASSERT_MESSAGE
To samo co instrukcja CPPUNIT_Assert, z tą różnicą, że w przypadku błędu zostanie zwrócony ciąg znaków na ekranie.
Poniższy test zgłosi błąd:
- void UnitTest::checkCondition_ValueOneSmallerThenValueTwo_ReturnTrue()
- {
- uint8_t value1ToPass = 50;
- uint8_t value2ToPass = 45;
- CPPUNIT_ASSERT_MESSAGE("Value 1 is bigger then value 2", checkCondition(value1ToPass, value2ToPass));
- }
W związku z tym, że została podana wiadomość to oprócz standardowych komunikatów zostanie wyświetlona zdefiniowana informacja:
CPPUNIT_FAIL
Wywołuje błąd z zdefiniowaną wiadomością:
- void UnitTest::checkCondition_ValueOneSmallerThenValueTwo_ReturnTrue()
- {
- uint8_t value1ToPass = 50;
- uint8_t value2ToPass = 45;
- uint8_t operationStatus = checkCondition(value1ToPass, value2ToPass);
- CPPUNIT_FAIL("Error MSG");
- }
Wygenerowany błąd wygląda następująco:
CPPUNIT_ASSERT_EQUAL
Następny warunek sprawdza czy wartości są sobie równe:
- void UnitTest::checkCondition_ValueOneSmallerThenValueTwo_ReturnTrue()
- {
- uint32_t value1ToPass = 50;
- uint32_t value2ToPass = 45;
- uint32_t expectedValue = value2ToPass * value1ToPass;
- uint32_t retValue = multipleValue(value1ToPass, value2ToPass);
- CPPUNIT_ASSERT_EQUAL(expectedValue, retValue);
- }
W przypadku błędu zostaną wyświetlone dokładne informacje wraz z otrzymanymi danymi o wartościach:
Działanie instrukcji podobne do poprzedniego, tym razem natomiast zostanie wyświetlona wiadomość w przypadku nieudanego testu. Przykładowy test:
Wartość otrzymana w przypadku błędu:
W tym przypadku sprawdzane jest czy w danej funkcji wywoływany jest wyjątek. Pod spodem testowana funkcja w języku C++:
Przeprowadzenie testów dla instrukcji warunkowych mogło by wyglądać następująco:
Ta asercja nie wyrzuca błędów dla niepoprawnych parametrów.
To samo co powyżej, tylko w przypadku błędu ma być wyświetlana informacja dla użytkownika.
Wywołanie błędu bez względu na wartość wprowadzonego parametru, warunku.
CPPUNIT_ASSERT_EQUAL
Działanie instrukcji podobne do poprzedniego, tym razem natomiast zostanie wyświetlona wiadomość w przypadku nieudanego testu. Przykładowy test:
- void UnitTest::checkCondition_ValueOneSmallerThenValueTwo_ReturnTrue()
- {
- uint32_t value1ToPass = 50;
- uint32_t value2ToPass = 45;
- uint32_t expectedValue = value2ToPass * value1ToPass + 5;
- uint32_t retValue = multipleValue(value1ToPass, value2ToPass);
- CPPUNIT_ASSERT_EQUAL_MESSAGE("Error value diff then expected", expectedValue, retValue);
- }
Wartość otrzymana w przypadku błędu:
CPPUNIT_ASSERT_DOUBLES_EQUAL
Głównym zadaniem tej funkcji jest sprawdzanie liczb zmiennoprzecinkowych z określoną dokładnością. Przykład asercji poniżej:
Gdy ustawimy mniejszą tolerancję i wynik będzie za bardzo rozbieżny to uzyskamy następującą informację o błędzie:
- void UnitTest::doublesEqual()
- {
- double const deltaExpected = 3.14;
- double const deltaCalculated = 22.0 / 7.0;
- double const maximumTolerance = 0.005;
- CPPUNIT_ASSERT_DOUBLES_EQUAL(deltaExpected, deltaCalculated, maximumTolerance);
- }
Gdy ustawimy mniejszą tolerancję i wynik będzie za bardzo rozbieżny to uzyskamy następującą informację o błędzie:
Drugi przypadek pozwala na sprawdzenie czy znaleźliśmy ilość licz z jakiegoś zakresu. Funkcja którą będę testował zlicza ilość odpowiednich wartości w tablicy do momentu otrzymania wartości 0xA2.
- static uint8_t countValuesInTable(uint8_t *table, uint8_t tableSize)
- {
- uint8_t countValue = 0;
- for(uint8_t i=0; i<tableSize; i++)
- {
- if(*(table + i) >= 0xA5)
- {
- countValue++;
- }
- else if(*(table + i) >= 0xA2)
- {
- return 0;
- }
- }
- return countValue;
- }
Projekt testowy wykorzystujący wspomnianą instrukcję może sprawdzać czy otrzymaliśmy ilość danych w zdefiniowanym zakresie:
Tutaj najpierw tworzymy nową tablicę następnie w funkcji zewnętrznej wprowadzamy wartości do tablicy z zakresu od 0 do 0xC8. Następnie wywołujemy funkcję zliczającą elementy w tablicy. Końcowy element czyli asercja sprawdza czy udało się odczytać ilość danych z podanego zakresu.
- void UnitTest::countValuesInTable_CheckIfValuesAreFromSelectedRange()
- {
- uint8_t table[200];
- prepareTableForFunc_countValuesInTable(&table[0], sizeof(table));
- uint8_t countedValues = countValuesInTable(&table[0], sizeof(table));
- CPPUNIT_ASSERT_DOUBLES_EQUAL(0xA0, countedValues, 0x0F);
- }
Tutaj najpierw tworzymy nową tablicę następnie w funkcji zewnętrznej wprowadzamy wartości do tablicy z zakresu od 0 do 0xC8. Następnie wywołujemy funkcję zliczającą elementy w tablicy. Końcowy element czyli asercja sprawdza czy udało się odczytać ilość danych z podanego zakresu.
CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE
Ta sama funkcja co wcześniej tylko z wyświetlaniem wiadomości. Zmieniony kod z wcześniejszego przykładu:
CPPUNIT_ASSERT_THROW
W tym przypadku sprawdzane jest czy w danej funkcji wywoływany jest wyjątek. Pod spodem testowana funkcja w języku C++:
- double checkValue(double checkValue)
- {
- if (checkValue < 0.0) {
- throw std::invalid_argument("Value must be bigger then 0");
- }
- else if(checkValue > 5){
- throw std::invalid_argument("Value must be lower then 5");
- }
- return checkValue * 3.14;
- }
Przeprowadzenie testów dla instrukcji warunkowych mogło by wyglądać następująco:
- void UnitTest::checkValue_LowerThenZero()
- {
- CPPUNIT_ASSERT_THROW(checkValue(-1), std::invalid_argument);
- }
- void UnitTest::checkValue_BiggerThenFive()
- {
- CPPUNIT_ASSERT_THROW(checkValue(6), std::invalid_argument);
- }
CPPUNIT_ASSERT_THROW_MESSAGE
To samo co powyżej tylko z dodatkową wiadomością w przypadku błędu. Zmodyfikowane testy z przykładu powyżej:
- void UnitTest::checkValue_LowerThenZero()
- {
- CPPUNIT_ASSERT_THROW_MESSAGE("No exception invalid_argument", checkValue(-1), std::invalid_argument);
- }
- void UnitTest::checkValue_BiggerThenFive()
- {
- CPPUNIT_ASSERT_THROW_MESSAGE("No exception invalid_argument", checkValue(6), std::invalid_argument);
- }
CPPUNIT_ASSERT_NO_THROW
Ta asercja nie wyrzuca błędów dla niepoprawnych parametrów.
CPPUNIT_ASSERT_NO_THROW_MESSAGE
To samo co powyżej, tylko w przypadku błędu ma być wyświetlana informacja dla użytkownika.
CPPUNIT_ASSERT_ASSERTION_FAIL
Wywołanie błędu bez względu na wartość wprowadzonego parametru, warunku.
- void UnitTest::assertionFail()
- {
- uint8_t value = 5;
- CPPUNIT_ASSERT_ASSERTION_FAIL(value = 15);
- }
CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE
To samo co powyżej tylko z wiadomością dla użytkownika.
- void UnitTest::assertionFail()
- {
- uint8_t value = 5;
- CPPUNIT_ASSERT_ASSERTION_FAIL_MESSAGE("Change parameter", value = 15);
- }
CPPUNIT_ASSERT_ASSERTION_PASS
Poprawne wykonanie asercji, bez względu na jej wynik. Chyba, że zostanie wyrzucony wyjątek.CPPUNIT_ASSERT_ASSERTION_PASS_MESSAGE
Asercja wykonuje się poprawnie, chyba że zostanie wyrzucony wyjątek. Wtedy wyświetli się informacja o nim oraz dodatkowa wiadomość przygotowana przez użytkownika.