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

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Arek (dyskusja | edycje)
Nie podano opisu zmian
 
Mirek (dyskusja | edycje)
Nie podano opisu zmian
 
(Nie pokazano 21 wersji utworzonych przez 4 użytkowników)
Linia 1: Linia 1:
{{cwiczenie|1||
 
Do przykładu testów <code><nowiki>max</nowiki></code> napisanych w
<code><nowiki>CppUnit</nowiki></code> dodaj testy sprawdzające wersję szukającą maksimum w
tablicy. Wykorzystaj w tym celu dodatkową klasę testującą.
Sprawdź swój test na implementacji [[media:Max_error.h | max_error.h]]. Znajdź znajdujące się tam błędy.
}}


''Uwaga: przekonwertowane latex2mediawiki; prawdopodobnie trzeba wprowadzi� poprawki''
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span><div class="mw-collapsible-content" style="display:none">
Patrz pliki [[media:Max_array_test.h | max_array_test.h]] i [[media:Max_cppunit.cpp | max_cppunit.cpp]].
</div></div>


{Klasy cech}
{{cwiczenie|2||


W poprzednich rozdziałach przedstawiono mechanizm typów związanych
Zaproponuj i napisz, używając <code><nowiki>CppUnit</nowiki></code>, testy
(czyli typedefów zagnieżdżonych wewnątrz klasy).
klasy <code><nowiki>Stack</nowiki></code>. Implementacja tej klasy znajduje się w pliku [[media:Stack.h | stack.h]]. Nie zapomnij o testach kopiowania i
Jest on intensywnie wykorzystywany w STL, gdzie bardzo przydaje się
przypisywania oraz destruktora.
do pisania szablonów funkcji parametryzowanych typem iteratora (albo
pojemnika).
Zagnieżdżony wewnątrz tego typu typ związany <code><nowiki> value_type</nowiki></code> pozwala na
tworzenie pomocniczych zmiennych przechowujących przetwarzane wartości,
<code><nowiki> iterator_category</nowiki></code>  pozwala wybrać odpowiednią wersję kodu,
i tak dalej.


Technika typów związanych ma jednak dwie wady.
Sprawdź czy stos zaimplementowany w pliku [[media:Stack_dyn.h | stack_dyn.h]], przechodzi twoje
Po pierwsze, muszą być one podczepione pod klasę, a czasem możemy chcieć
testy.  Jeśli tak, to znajdź błędy w kodzie i tak popraw testy, aby
uzyskać informacje na temat czegoś, co może być albo klasą, albo prostym
wyłapywały te błędy. Popraw kod tak, aby przeszedł uzupełnione testy.
typem wbudowanym (patrz iteratory -- albo klasy, albo zwykłe wskaźniki).
}}
Po drugie, lista przekazywanych informacji jest zamknięta; aby
coś dodać, trzeba mieć dostęp do kodu źródłowego i go zmodyfikować.
Rozwiązaniem obu problemów są szablony cechujące.


'''Zadanie 1 '''
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span><div class="mw-collapsible-content" style="display:none">
Zaimplementuj funkcję uogólnioną biorącą jako argumenty parę iteratorów,
Test stosu podzielę na cztery części: pierwsza zawierać będzie test
i zwracającą najmniejszy z tego ciągu elementów.
podstawowych funkcji, druga - destruktora, a trzecia i czwarta -
Najpierw opracuj wersję wykorzystującą typ związany, a potem wersję
konstruktora kopiującego i operatora przypisania.
korzystającą ze standardowego szablonu cechującego <code><nowiki> iterator_traits</nowiki></code> .
Sprawdź działanie obu wersji na liście oraz na zwykłej tablicy.
Przypominajka: w obu przypadkach niezbędne będzie słówko kluczowe
<code><nowiki> typename</nowiki></code> .


'''Zadanie 2 '''
Test podstawowy zawarty jest w składowej <tt>test_base()</tt> klasy <tt>stack_test</tt> w pliku [[media:Stack_test_cppunit.cpp | stack_test_cppunit.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.
Zapoznaj się z plikiem <code><nowiki> kategorie.cpp</nowiki></code> .
Jest w nim przedstawiony sposób selekcji jednej spośród kilku implementacji
algorytmu na podstawie możliwości oferowanych przez przekazany iterator;
w tym konkretnym przykładzie rozróżniamy dwie grupy: iteratory o swobodnym
dostępie oraz wszystkie inne.
Rozszerz kod tak, aby wybierana była jedna z trzech możliwości: swobodny
dostęp, dwukierunkowe, gorsze niż dwukierunkowe.


'''Zadanie 3 '''
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ć implementacja [[media:Stack_dyn.h | stack_dyn.h]]. 
Opierając się na przykładowym kodzie z poprzedniego zadania zaimplementuj
wariantowy algorytm sortowania ciągów.
Dla iteratorów jednokierunkowych użyj sortowania przez prosty wybór (patrz
odpowiednie ćwiczenie w module 3);
dla tych o dostępie swobodnym użyj quicksortu.


'''Zadanie 4 '''
Zacznijmy od destruktora. Zadaniem destruktora jest usunięcie pamięci zajętej przez stos, a objawem błędu 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.
Do jakichś bliżej nie znanych celów potrzebny jest sposób na odróżnianie
iteratorów będących zwykłymi, klasycznymi wskaźnikami od wszystkich
pozostałych.
Ponieważ biblioteka standardowa nie dostarcza odpowiedniego mechanizmu,
trzeba go samodzielnie stworzyć.
Zaimplementuj szablon cechujący o nazwie <code><nowiki> is_pointer</nowiki></code> , zawierający
składową boolowską <code><nowiki> value</nowiki></code> .


'''Podpowiedź do zadania 4 '''
    try {
Stwórz ogólny szablon zawsze zwracający <code><nowiki> false</nowiki></code> , a potem wyspecjalizuj
      for(int i<nowiki> =</nowiki>   0;i<1000;i++) {
go dla typów będących wskaźnikiem do czegoś i tam zwracaj <code><nowiki> true</nowiki></code> .
          Stack<double,1000000> s;
      }
    } catch(std::bad_alloc &) {
      CPPUNIT_ASSERT(0);
    };


'''Rozwiązanie 4 '''
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 <tt>operator new</tt> rzuci wyjątek. Oczywiście jeśli wyciek będzie mały np. parę bajtów, to ta metoda go nie wychwyci.
Patrz plik <code><nowiki> czy_wsk.cpp</nowiki></code> .
 
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ę <tt>equal</tt>, która porównuje dwa stosy, opróżniając je, a następnie uzupełniając z powrotem. Kod znajduje się w pliku [[media:Stack_test_cppunit.cpp | stack_test_cppunit.cpp]].
 
Częstym błędem 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ę <tt>inc</tt>, która zwiększa każdy element stosu liczb całkowitych  o jeden. W przypadku współ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 [[media:Stack_test_cppunit.cpp | stack_test_cppunit.cpp]].
</div></div>

Aktualna wersja na dzień 15:45, 2 paź 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 max_error.h. Znajdź znajdujące się tam błędy.

Rozwiązanie

Ć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 stack_dyn.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