- Komunikuje się z bazą danych
- Komunikuje się po przez sieć
- Pracuje z systemem plików
- Nie może być uruchomiony równolegle z innymi testami
- Musisz dokonać zmian w środowisku uruchomieniowym, aby zadziałał
- Testowana baza danych zazwyczaj nie jest idealnym odzwierciedleniem bazy produkcyjnej
- Tworząc bazę testową należy wziąć pod uwagę następujące czynniki:
- Jak bardzo ustawienia bazy testowej są zbliżone do bazy produkcyjnej
- Na ile łatwo jest współdzielić konfigurację w zespole
- Na ile łatwy jest dostęp do bazy
- Zawsze czyść bazę danych przed testem, a nie po jego wykonaniu
- Stwórz klasę wspierającą testowanie, która będzie zajmowała się czyszczeniem bazy danych
1) Wzorce asercji
Wzorce te zostały zebrane i opisane przez Gerarda Meszaros http://xunitpatterns.com/
Wzorce asercji można podzielić na:
- Asercja stanu końcowego – sprawdza stan końcowy
- Asercja pomocnicza - programista upewnia się, że obiekt, który tworzy, ma odpowiedni stan
- Asercja delta – badana jest różnica między stanem początkowym a końcowym
- Własna asercja
- Asercja interakcji
Programowa realizacja tych wzorców przejawia się w metodach klasy Assert. Metody te zostały opisane w podpunkcie IV.2
http://premium-hands.blogspot.com/2011/11/normal-0-21-false-false-false-pl-x-none.html
My skupimy się tylko na dwóch ostatnich typach.
Własna asercja (Custom Assertion) – jeśli używasz wielokrotnie tej samej asercji lub asercja jest złożona warto wyodrębnić metodę – własną asercję. Może się to wydawać oczywiste, ale warto o tym wspomnieć. Asercja własna jest najczęściej wynikiem refaktoryzacji kodu. Przypomnijmy, refaktoryzacji nie podlega tylko właściwy kod aplikacji, ale także kod testowy.
Asercja interakcji (Interaction Assertion) – zamiast badać stan bada się interakcję obiektów testowanych. Do tego celu głównie używa się Mock Objects. Tym sposobem możemy sprawdzić wywołanie konkretnej metody, parametry z jakimi została wywołana, a także kolejność wywołań. Testowanie interakcji stosuje się dla testów złożonych, gdzie ze względu na trudność realizacji testowanie stanu jest bardzo trudne.
2. Wzorce otoczenia testu
Otoczenie testu (test fixture) – otoczenie testu to warunki początkowe wspólne dla kilku testów. Otoczenie testu nadaje kontekst dla testów, które do niego przynależą. Jest realizowane po przez pola klasy testu i inicjację w metodzie oznaczonej atrybutem [SetUp] TODO: Poszukać atrybutu dla VS TeamTest. Otoczenie testu minimalizuje duplikację, wyodrębnia cechy wspólne wielu testów w formie pól i metody SetUp. Dobrze przemyślane rozwiązanie spowoduje, iż metody testowe będą się składać z prostych wywołań i asercji. Warto także wspomnieć, iż atrybut opisujący klasę testową w NUnit to [TestFixture].
Metoda fabryki (Parameterized Creation Method) – zamiast budować stan obiektów za każdym razem wypełniając wiele pól, warto wyodrębnić metodę pomocniczą, która pomoże stworzyć wymagane obiekty
- Często podczas testowania należy tworzyć wiele pomocniczych obiektów
- Stwórz metodę pomocniczą – metodę fabryki, która zajmie się szczegółami przygotowania obiektów do testu, które nie mają większego znaczenia
- Czasami wystarczy wykorzystać odpowiedni konstruktor, jeśli istnieje lub stworzyć nowy
Klasy pomocnicze
- Dodatkowo przydają się również pomocnicze klasy, które upraszczają tworzenie obiektów, np. generator unikalnych identyfikatorów (np. generator imion i nazwisk)
Matka obiektów
- Klasa fabryki stworzona na potrzeby testów
- Zawiera metody kreacyjne
- Zawiera metody zmieniające stan obiektów (np. zamówione – złożone, zaakceptowane oczekujące zrealizowane)
- Zbiera metody pomocnicze ułatwiające tworzenie obiektów na potrzeby testów
- Może być to jedna klasa lub kilka klas
- Klasy te mogą powstawać w efekcie refaktoryzacji testów
Automatyczne porządki (Automated teardown)
- Sprzątanie po teście w przypadku złożonych danych jest nietrywialnie – łatwo zapomnieć o stworzonych obiektach
- Tworzy się rejestr obiektów, do którego trafiają wszystkie obiekty tworzone w [SetUp], które należy usunąć po zakończeniu testu [TearDown]
3. Wzorce klas testowych:
Autopodstawienie (Self-Shunt)
- Klasa testowa implementuje interfejs, który ma stanowić imitację (Test double)
- Pozwala uniknąć tworzenia dodatkowych klas
- Zaciemnia konstrukcję
- Przydatne w prostych przypadkach
Uprzywilejowany dostęp (Privileged Access)
- Bezpośrednie testowanie metod prywatnych jest w NUnit niemożliwe
- Można skorzystać z refleksji do wywołania metod prywatnych
- Nie powinno się nadużywać tej techniki
- Zbyt wiele metod prywatnych, które należy przetestować, może sugerować refaktoryzację Wydzielenie klasy.
Dodatkowy konstruktor (Extra Constructor)
- Jeśli kod, który testujesz ma zależności zaszyte wewnątrz klasy, trudno będzie go testować w izolacji
- Stwórz dodatkowy konstruktor, który pozwoli dostarczać dane z zewnątrz
- W teście użyj nowego konstruktora
III. Elementy testowanego kodu
1. Kompozycja zamiast dziedziczenia
Dziedziczenie jest jednym ze sposobów rozdzielenia odpowiedzialności między klasami. Umożliwia dodanie lub zmianę zachowania w klasie. Wadą jest to, że przeciążane metody mają tendencję do dużej zależności od klasy, w której się znajdują. Oznacza to, że zazwyczaj obciążone są pewnymi założeniami (np. metoda intensywnie korzysta z wewnętrznego stanu obiektu). Klasy dziedziczące mają tendencję także do rozrastania się. Często okazuje się że pewne elementy z klas nadrzędnych nie są potrzebne w klasach podrzędnych. Klasy są ze sobą mocno powiązane dziedziczeniem co utrudnia używanie test double.
Dzięki kompozycji klasa deleguje założone zadania do innych komponentów. Następuje lepsze rozłożenie odpowiedzialności. W testach możemy używać test doubles w miejscu klas zależnych. Poniważ klasy są mniejsze łatwiej testować je jednostkowo.2. Unikanie elementów statycznych
Elementy statyczne mają szereg wad, które mogą utrudniać testowanie:
- Elementy statyczne mają charakter globalny (są związane z klasą a nie z obiektem)
- Elementy statyczne nie podlegają dziedziczeniu
- Nie można zastosować do nich test double
- Testowanie w pełni jednostkowe jest niemożliwe
- Zależność jest zaszyta wewnątrz metody
- Architektura warstwowa sprzyja testowaniu
- Powinny być wydzielone przynajmniej 3 warstwy
- Interfejs użytkownika
- Logika biznesowa
- Dostęp do danych
- Klasy wizualne interfejsu nie powinny zawierać żadnej logiki przetwarzania. Logikę UI należy przenieść do obiektów pomocniczych
- Automatyczne – wykonują się bez udziału człowieka
- Zupełne – obejmują wszystkie istotne przypadki testowe
- Powtarzalne – mogą być uruchamiane wielokrotnie
- Niezależne – nie powinny zależeć od zmian w środowisku zewnętrznym testu
- Profesjonalnie – kod testu powinien być napisany równie starannie, jak kod produkcyjny
- Ogół
Najpierw testy wysokiego poziomu – tworzonych jest wiele testów bez początkowego wchodzenia w szczegóły.
Zalety:
- Większe zrozumienie całościowe systemu
- Szczegół
Dany test jest rozwijany tak długo, aż nie osiągnie się ostatecznego, pełnego rozwiązania.
Zalety:
- Szybka eliminacja ryzyka, gdyż rozpoznawane są szczegóły problemu
Ad.b Znane - nieznane
- Znane
Najpierw wybierane są te testy, które sprawdzają typowe elementy funkcjonalności, które są łatwo przewidywalne,
Zalety:
- Jednoznaczne ścieżka prowadząca dająca szybkie efekty
- Nieznane
Najpierw wybierane są te testy, które obejmują mniej typowe przypadki
Zalety:
- Wczesna analiza i potencjalna eliminacja ryzyka – zostaną szybko wykryte te elementy których nie da się wykonać lub będzie to nieopłacalne
Note:
Nie warto stosować kiedy nietypowe przypadki są bardzo mało prawdopodobne lub nie mają wpływu na system.
Ad.c Ścieżka pozytywna ścieżka negatywna
- Ścieżka pozytywna
Testowane są scenariusze typowego, zakończonego powodzeniem działania metody lub funkcji.
Zalety:
- Testowane jest to, co przydarza się najczęściej
- Ścieżka negatywna
Testowane są scenariusze sytuacji wyjątkowych, na które system powinien być przygotowany
Zalety:
- Minimalizowane jest ryzyko wynikające z błędów użytkownika lub programisty
Note:
Zazwyczaj najpierw warto wybrać testowanie z użyciem ścieżki pozytywnej, a następnie ścieżki negatywnej
Jak to połączyć w praktyce?
- Zacznij od prostego i oczywistego testu (sunny day scenario)
- proste podstawienia, typowy scenariusz - Testuj każdą funkcję z uwagą.
- Zastanów się czy dana funkcja jest istotna z punktu widzenia systemu i jeśli tak, to, dlaczego - Najpierw testuj ogólnie, a następnie szczegółowo
- W ten sposób odnajdziesz najbardziej newralgiczne punkty systemu - Po przetestowaniu podstawowego scenariusza, wybierz trudne ścieżki (nieznane lub negatywne)
0 komentarze:
Prześlij komentarz