Zaawansowane CPP/Ćwiczenia 4: Testowanie: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Mirek (dyskusja | edycje)
Nie podano opisu zmian
Mirek (dyskusja | edycje)
Nie podano opisu zmian
Linia 4: Linia 4:
<code><nowiki>CppUnit</nowiki></code> dodaj testy sprawdzające wersję szukającą maksimum w
<code><nowiki>CppUnit</nowiki></code> dodaj testy sprawdzające wersję szukającą maksimum w
tablicy. Wykorzystaj w tym celu dodatkową klasę testującą.
tablicy. Wykorzystaj w tym celu dodatkową klasę testującą.
}}
Sprawdź
swój test na implementacji {mod09/exercises/max_error.h}<tt>maxerror.h</tt>. Znajdź znajdujące się tam błędy.
}}
 
 
{{cwiczenie|2||
{{cwiczenie|2||


Zaproponuj i napisz, używając <code><nowiki>CppUnit</nowiki></code>, testy
Zaproponuj i napisz, używając <code><nowiki>CppUnit</nowiki></code>, testy
klasy <code><nowiki>Stack</nowiki></code>.  Implementacja tej klasy znajduje się w pliku [http://osilek.mimuw.edu.pl/images/6/61/Stack.h stack.h]. Nie zapomnij o testach kopiowania i
klasy <code><nowiki>Stack</nowiki></code>.  Implementacja tej klasy znajduje się w pliku [http://osilek.mimuw.edu.pl/images/6/61/Stack.h stack.h]. Nie zapomnij o testach kopiowania i
przypisywania.
przypisywania oraz destruktora.
 
Sprawdź czy stos zaimplementowany w pliku
{mod09/exercises/stack_dyn.h}<tt>stackdyn.h</tt>, przechodzi twoje
testy.  Jeśli tak, to znajdź błędy w kodzie i tak popraw testy, aby
wyłapywały te błędy.  Popraw kod tak, aby przeszedł uzupełnione testy.
}}
}}
{{cwiczenie|3||


W oparciu o specyfikację <code><nowiki>slist</nowiki></code> napisz program (niekoniecznie
 
używając <code><nowiki>CppUnit</nowiki></code>) testujący implementację listy jednokierunkowej
'''Rozwiązanie 1 '''
<code><nowiki>slist</nowiki></code>. Przetestuj test za pomocą implementacji listy
 
[ badslist.h]. Ile znalazłeś błędów?
Zobacz plik
}}
{mod09/exercises/max_array_test.cpp}<tt>maxarraytest.cpp</tt> i
{mod09/exercises/max_cppunit.cpp}<tt>maxcppunit.cpp</tt>.
 
'''Rozwiązanie 2 '''
 
Test stosu podzielę na cztery części: pierwsza zawierać będzie test
podstawowych funkcji, druga destruktora, a trzecia i czwarta
konstruktora kopiującego i operatora przypisania.
 
Test podstawowy zawarty jest w składowej {test_base()} klasy
{stack_test} w pliku
{mod09/exercises/stack_test_cppunit.cpp}<tt>stacktestcppunit.cpp</tt>.  Polega on na naprzemiennym wkładaniu i
zdejmowaniu ze stosu liczb całkowitych i sprawdzaniu poprawności
zdejmowanych elementów.  Na końcu trzykrotnie wypełniamy i opróżniamy
cały stos.
 
Pozostałe testy wymagają więcej komentarza. Ich zadaniem jest
testowanie funkcji generowanych automatycznie. W tym przypadku
działają one prawidłowo, co można dość łatwo stwierdzić bez
przeprowadzania testów. W ogólności jednak nie musi tak być.
Przykładem może być implementacj {stac_dyn.h}. 
 
Zacznijmy od  destruktora, zadaniem destruktora jest usunięcie pamięci
zajętej przez stos, a objawem błedu w destruktorze jest wyciek pamięci.
 
Nie znam uniwersalnego sposobu testowania wycieku pamięci. Zwykle
używam prostej, ale ograniczonej sztuczki. Polega ona na tworzeniu i
niszczeniu dużego stosu w dużej pętli.
 
    try {
      for(int i<nowiki> =</nowiki>   0;i<1000;i++) {
Stack<double,1000000> s;
      }
    } catch(std::bad_alloc &) {
      CPPUNIT_ASSERT(0);
    };
Jeśli destruktor nie zwolni pamięci, to w każdej iteracji następował
będzie wyciek, i pamięci w końcu zabraknie. Wtedy kolejne wywołanie
{operator new} rzuci wyjątek. Oczywiście jeśli wyciek będzie mały
np. parę bajtów, to ta metoda go nie wychwyci.
 
Testy kopiowania i przypisania wyglądają podobnie. W obu przypadkach
wynikiem powinny być dwa stosy o takiej samej zawartości.  Proszę
jednak zauważyć, że nie posiadamy możliwości bezpośredniego porównania
zawartości stosów bez opróżniania ich.  Nawet zresztą gdybyśmy mieli
operator porównia, to i tak wymagałby on testowania.  W tym celu
napisałem funkcję {equal} która porównuje dwa stosy, opróżniając
je, a następnie uzupęłniając z powrotem. Kod znajduję się w pliku
{mod09/exercises/stack_test_cppunit.cpp}<tt>stacktestcppunit.cpp</tt>.
 
Częstym błedem podaczas kopiowania/przypisywania jest doprowadzenie do
współdzielenia reprezentacji. Musimy więc sprawdzić, czy dwie kopie nie
tylko są równe ale i niezależne. W tym celu napisałem funkcję {inc}
która zwiększa każdy element stosu liczb całkowitych  o jeden.
W przypadku wspołdzielenia reprezentacji nastąpi zwiększenie obu
stosów i oba stosy dalej będą równe.  
 
Dodatkowo w trakcie przypisywania może dojść do wycieku pamięci
w stosie, do którego przypisujemy nową wartość. Testujemy to
podobnie jak w przypadku destruktora.  
 
Całość kodu znajduje się w pliku
{mod09/exercises/stack_test_cppunit.cpp}<tt>stacktestcppunit.cpp</tt>.

Wersja z 21:05, 26 wrz 2006

Ćwiczenie 1

Do przykładu testów max napisanych w CppUnit dodaj testy sprawdzające wersję szukającą maksimum w tablicy. Wykorzystaj w tym celu dodatkową klasę testującą. Sprawdź swój test na implementacji {mod09/exercises/max_error.h}maxerror.h. Znajdź znajdujące się tam błędy.


Ćwiczenie 2

Zaproponuj i napisz, używając CppUnit, testy klasy Stack. Implementacja tej klasy znajduje się w pliku stack.h. Nie zapomnij o testach kopiowania i przypisywania oraz destruktora.

Sprawdź czy stos zaimplementowany w pliku {mod09/exercises/stack_dyn.h}stackdyn.h, przechodzi twoje testy. Jeśli tak, to znajdź błędy w kodzie i tak popraw testy, aby wyłapywały te błędy. Popraw kod tak, aby przeszedł uzupełnione testy.


Rozwiązanie 1

Zobacz plik {mod09/exercises/max_array_test.cpp}maxarraytest.cpp i {mod09/exercises/max_cppunit.cpp}maxcppunit.cpp.

Rozwiązanie 2

Test stosu podzielę na cztery części: pierwsza zawierać będzie test podstawowych funkcji, druga destruktora, a trzecia i czwarta konstruktora kopiującego i operatora przypisania.

Test podstawowy zawarty jest w składowej {test_base()} klasy {stack_test} w pliku {mod09/exercises/stack_test_cppunit.cpp}stacktestcppunit.cpp. Polega on na naprzemiennym wkładaniu i zdejmowaniu ze stosu liczb całkowitych i sprawdzaniu poprawności zdejmowanych elementów. Na końcu trzykrotnie wypełniamy i opróżniamy cały stos.

Pozostałe testy wymagają więcej komentarza. Ich zadaniem jest testowanie funkcji generowanych automatycznie. W tym przypadku działają one prawidłowo, co można dość łatwo stwierdzić bez przeprowadzania testów. W ogólności jednak nie musi tak być. Przykładem może być implementacj {stac_dyn.h}.

Zacznijmy od destruktora, zadaniem destruktora jest usunięcie pamięci zajętej przez stos, a objawem błedu w destruktorze jest wyciek pamięci.

Nie znam uniwersalnego sposobu testowania wycieku pamięci. Zwykle używam prostej, ale ograniczonej sztuczki. Polega ona na tworzeniu i niszczeniu dużego stosu w dużej pętli.

   try {
     for(int i =   0;i<1000;i++) {

Stack<double,1000000> s;

     }
   } catch(std::bad_alloc &) {
     CPPUNIT_ASSERT(0);
   };

Jeśli destruktor nie zwolni pamięci, to w każdej iteracji następował będzie wyciek, i pamięci w końcu zabraknie. Wtedy kolejne wywołanie {operator new} rzuci wyjątek. Oczywiście jeśli wyciek będzie mały np. parę bajtów, to ta metoda go nie wychwyci.

Testy kopiowania i przypisania wyglądają podobnie. W obu przypadkach wynikiem powinny być dwa stosy o takiej samej zawartości. Proszę jednak zauważyć, że nie posiadamy możliwości bezpośredniego porównania zawartości stosów bez opróżniania ich. Nawet zresztą gdybyśmy mieli operator porównia, to i tak wymagałby on testowania. W tym celu napisałem funkcję {equal} która porównuje dwa stosy, opróżniając je, a następnie uzupęłniając z powrotem. Kod znajduję się w pliku {mod09/exercises/stack_test_cppunit.cpp}stacktestcppunit.cpp.

Częstym błedem podaczas kopiowania/przypisywania jest doprowadzenie do współdzielenia reprezentacji. Musimy więc sprawdzić, czy dwie kopie nie tylko są równe ale i niezależne. W tym celu napisałem funkcję {inc} która zwiększa każdy element stosu liczb całkowitych o jeden. W przypadku wspołdzielenia reprezentacji nastąpi zwiększenie obu stosów i oba stosy dalej będą równe.

Dodatkowo w trakcie przypisywania może dojść do wycieku pamięci w stosie, do którego przypisujemy nową wartość. Testujemy to podobnie jak w przypadku destruktora.

Całość kodu znajduje się w pliku {mod09/exercises/stack_test_cppunit.cpp}stacktestcppunit.cpp.