Testowanie II. Cel zajęć. Pokrycie kodu

Podobne dokumenty
Testowanie II. Celem zajęć jest zapoznanie studentów z oceną jakości testów przy wykorzystaniu metryk pokrycia kodu testami (ang. code coverage).

METODY PROGRAMOWANIA

JUnit TESTY JEDNOSTKOWE. Waldemar Korłub. Platformy Technologiczne KASK ETI Politechnika Gdańska

Programowanie obiektowe

Testowanie I. Celem zajęć jest zapoznanie studentów z podstawami testowania ze szczególnym uwzględnieniem testowania jednostkowego.

Programowanie poprzez testy z wykorzystaniem JUnit

Programowanie zespołowe

LABARATORIUM 9 TESTY JEDNOSTKOWE JUNIT 3.8

Aplikacje w środowisku Java

Platformy Technologiczne

TEMAT : KLASY DZIEDZICZENIE

Testy automatyczne. Korzystające z junit

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL IV TI 6 godziny tygodniowo (6x15 tygodni =90 godzin ),

Programowanie Obiektowe Ćwiczenie 4

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Klasy i obiekty cz II

Wywoływanie metod zdalnych

Wątki w Javie. Piotr Tokarski

Instrukcja 10 Laboratorium 13 Testy akceptacyjne z wykorzystaniem narzędzia FitNesse

Programowanie obiektowe

Ćwiczenie 1. Kolejki IBM Message Queue (MQ)

Wyjątki. Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut.

Wywoływanie metod zdalnych

Rozdział 4 KLASY, OBIEKTY, METODY

Instrukcje wyboru. Tworzenie programu, Schematy blokowe, Instrukcje wyboru, Operatory logiczne

Wprowadzenie do testów jednostkowych. Marcin Dziedzic, Wiktor Żołnowski

TESTOWANIE OPROGRAMOWANIA

4. Funkcje. Przykłady

Testy jednostkowe - zastosowanie oprogramowania JUNIT 4.0 Zofia Kruczkiewicz

lekcja 8a Gry komputerowe MasterMind

Instrukcje wyboru. Tworzenie programu, Schematy blokowe, Instrukcje wyboru, Operatory logiczne

Autor: dr inż. Zofia Kruczkiewicz, Programowanie aplikacji internetowych 1

Współbieżność w środowisku Java

Metody Metody, parametry, zwracanie wartości

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania

PHP 5 język obiektowy

Obsługa błędów za pomocą wyjątków. Paweł Motofa (140746)

Język JAVA podstawy. wykład 2, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Testowanie oprogramowania. Testowanie oprogramowania 1/34

Zadanie polega na stworzeniu bazy danych w pamięci zapewniającej efektywny dostęp do danych baza osób.

Układy VLSI Bramki 1.0

Zaawansowane aplikacje WWW - laboratorium

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Katedra Architektury Systemów Komputerowych Wydział Elektroniki, Telekomunikacji i Informatyki Politechniki Gdańskiej

Dokumentacja do API Javy.

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

INŻYNIERIA OROGRAMOWANIA TESTOWANIE JEDNOSTKOWE 2015/2016

Testowanie aplikacji JAVA Laboratorium 8 (Tabele w scenariuszach JBehave. Projekt z podstaw BDD oraz atrap.)

Aplikacje w środowisku Java

Aplikacje w Javie- wykład 11 Wątki-podstawy

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Algorytmy i Struktury Danych. Anna Paszyńska

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]


ALGORYTMY I STRUKTURY DANYCH

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Modelowanie obiektowe

Programowanie obiektowe i C++ dla matematyków

Laboratorium z przedmiotu: Inżynieria Oprogramowania INP002017_ Laboratorium 11 Testy akceptacyjne z wykorzystaniem narzędzia FitNesse

1 Wskaźniki i zmienne dynamiczne, instrukcja przed zajęciami

Języki i metody programowania Java INF302W Wykład 3 (część 1)

Diagramy stanów tworzenie modeli analizy i projektowania Na podstawie UML 2.0 Tutorial

Podstawy i języki programowania

Testowanie aplikacji Java Servlets

C++ Przeładowanie operatorów i wzorce w klasach

Zmienne powłoki. Wywołanie wartości następuje poprzez umieszczenie przed nazwą zmiennej znaku dolara ($ZMIENNA), np. ZMIENNA=wartosc.

Aplikacje w środowisku Java

Programowanie obiektowe

Aplikacje RMI

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

Podejście obiektowe do budowy systemów rozproszonych

Java RMI. Dariusz Wawrzyniak 1. Podejście obiektowe do budowy systemów rozproszonych. obiekt. interfejs. kliencka. sieć

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Java. Wykład. Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

KRYPTOGRAFIA I OCHRONA DANYCH PROJEKT

Programowanie obiektowe

Typy, klasy typów, składnie w funkcji

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.

Wprowadzenie do Behaviordriven

Programowanie kontraktowe w Javie

Wprowadzenie do projektu QualitySpy

Wyrażenie include(sciezka_do_pliku) pozwala na załadowanie (wnętrza) pliku do skryptu php. Plik ten może zawierać wszystko, co może się znaleźć w

Programowanie komputerowe. Zajęcia 4

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Testowanie oprogramowania

Java RMI. Dariusz Wawrzyniak 1. Podejście obiektowe do budowy systemów rozproszonych. obiekt. interfejs. kliencka. sieć

Narzędzia i aplikacje Java EE. Usługi sieciowe Paweł Czarnul pczarnul@eti.pg.gda.pl

Aplikacje RMI Lab4

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

KLASY, INTERFEJSY, ITP

dr inż. Piotr Czapiewski Tworzenie aplikacji w języku Java Laboratorium 1

Automaty do zadań specjalnych. Olga Maciaszek-Sharma, Artur Kotow Wersja 1,

Katalog książek cz. 3: Web Service

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Inżynieria Programowania - Testowanie oprogramowania cz.2

Remote Method Invocation 17 listopada 2010

Wykład 12. Programowanie serwera MS SQL 2005 w C#

Transkrypt:

Cel zajęć Celem zajęć jest zapoznanie studentów z uzupełniającymi zagadnieniami dotyczącymi testowania wytwarzanego oprogramowania. W pierwszej części zajęć przedstawiona zostanie metoda oceny kompletności i jakości testów przy użyciu metryk pokrycia kodu (ang. code coverage), w drugiej natomiast koncepcja atrap obiektów (ang. mock objects) pomocnych przy testowaniu jednostkowym klas trudnych do odseparowania od reszty systemu. Pokrycie kodu Jak już była mowa na poprzednich zajęciach testy nie są w stanie zagwarantować, że w oprogramowaniu nie ma błędów. Trzeba jednak się zastanowić, czy można zrobić coś, aby nasze testy znajdowały jak największą liczbę błędów? Czy można w jakiś sposób sprawdzić jakość i kompletność naszych testów (przez jakość rozumiemy tutaj znalezienie jak największej ilości błędów)? Jednym ze sposobów mierzenia jakości testów jest sprawdzanie pokrycia kodu. Możemy wyróżnić między innymi: pokrycie wyrażeń/linii (ang. statement/line coverage) sprawdza czy sterowanie przeszło przez każde wyrażenie dostępne w kodzie public int additems(list items) { if (items!= null) { list.addall(items); return list.size(); Test, który gwarantuje 100% pokrycia kodu: public void testadditems() { assertequals(3, someobject.additems(new ArrayList())); pokrycie decyzji (ang. decision coverage) sprawdza, czy każde wyrażenie logiczne przyjęło wartość true i false. Całe wyrażenie logiczne jest brane w tym przypadku pod uwagę, bez względu na podwyrażenia logiczne połączone operatorami AND (&&) lub OR ( ). public int additem(object item) { if (item!= null) { list.add(item); return list.size(); Następujący test gwarantuje 50% pokrycia decyzji, gdyż warunek w instrukcji warunkowej przyjmuje jedynie wartość true: strona 1 / 7

public void testadditem() { assertequals(1, someobject.additem(new Object())); pokrycie warunków (ang. condition coverage) podobne do pokrycia decyzji, bierze jednak pod uwagę wartości jakie przyjmują podwyrażenia logiczne pokrycie ścieżek (ang. path coverage) weryfikuje, czy każda możliwa ścieżka została sprawdzona public int calculate() { int result = 0; if (a > 0) { result += a; if (b > 0) { result += b; return result; Następujący test gwarantuje 25% pokrycia ścieżek, gdyż tylko jedna z czterech możliwych ścieżek została sprawdzona: public void testcalculate() { Object.a = 2; object.b = 0; assertequals(2, object.calculate()); Dopiero następujący test gwarantuje 100% pokrycia ścieżek public void testcalculate() { object.a = 2; object.b = 0; assertequals(2, object.calculate()); object.a = 0; object.b = 0; assertequals(0, object.calculate()); object.a = 3; object.b = 1; assertequals(4, object.calculate()); object.a = 0; object.b = 1; assertequals(1, object.calculate()); pokrycie metod (ang. method coverage) sprawdza, czy wszystkie dostępne metody zostały wywołane podczas testowania pokrycie klas (ang. class coverage) sprawdza, czy wszystkie klasy zostały chociaż raz zainicjalizowane strona 2 / 7

Wybrane problemy Sprawdzanie pokrycia kodu testami daje nam pewną informację o jakości naszych testów, nie możemy jednak polegać na nim całkowicie. Poniżej przedstawione zostały sytuacje, które pokazują, że takie podejście może być czasem mylące: 1. Pełne pokrycie kodu testami nie gwarantuje jakości! public List addobject(list list, Object o) { if (list!= null) { list.add(o); return list; Następujący test gwarantuje 100% pokrycia wyrażeń, decyzji, warunków, metod, klas, ale nic tak naprawdę nie testuje, bo nie ma w nim żadnej asercji: public void testaddobject() { object.addobject(new ArrayList(), new Object()); object.addobject(null, null); public int multiply(int x, int y) { return x + y; Następujący test gwarantuje 100% pokrycia wyrażeń, decyzji, warunków, metod, klas, ale źle dobrane dane wejściowe powodują, że test nie wykrywa błędu: public void testadd() { assertequals(4, object.multiply(2, 2)); 2. Czasami nie jest możliwe osiągnięcie pełnego pokrycia kodu. 3. Problem z testowaniem pętli. Czy aby na pewno wystarczy, jeśli kod pętli zostanie wykonany tylko raz? Zadania 1. Napisz na kartce test, który zapewnia 100% pokrycie decyzji w poniższym kodzie: public int countuniqueelements(list<string> elements) { if (elements == null) { return 0; HashMap<String, Object> uniqueelements = new HashMap<String, Object>(); for (String element : elements) { strona 3 / 7

if (!uniqueelements.containskey(element)) { uniqueelements.put(element, null); return unigueelements.size(); 2. Podaj przykład kodu, dla którego nie jest możliwe napisanie testu dającego 100% pokrycia ścieżek programu. Mock objects Testowanie jednostkowe opiera się na tworzeniu przypadków testowych dla pojedynczych klas. Dla każdej testowanej klasy tworzona jest klasa testująca, której metody wywołują poszczególne metody z obiektu klasy testowanej sprawdzając np. czy dla wskazanych parametrów zwracana przez metodę wartość jest poprawna. Podejście to jest wystarczające w przypadku prostych klas. Problemy zaczynają się gdy istnieje wiele powiązań między klasą testowaną a innymi klasami z systemu: 1. Jeżeli klasa testowana wymaga współpracy z dużą liczbą innych klas może się okazać, iż w metodzie konfigurującej dany test (oznaczonej adnotacją @Before) musimy uruchamiać sporą część systemu co może znacząco wydłużyć proces testowania. 2. Ciężko jest też testować kod, który korzysta z zasobów zewnętrznych, np. baz danych, połączenia z serwerem itp. Wiąże się to nie tylko z wydłużeniem trwania takich testów, lecz również może dojść do zakłamania testów np. dane w bazie mogą się różnić od oczekiwanych lub mogą występować problemy z połączeniem internetowym, przez co testy mogą się nie powieść. 3. Testowanie klasy w oderwaniu od reszty systemu może być trudne lub wręcz niemożliwe. Z pomocą przychodzą nam atrapy obiektów, tzw. mocki. Służą do zastępowania nimi rzeczywistych obiektów, tak by inne klasy nie zauważyły różnicy między prawdziwym obiektem a atrapą. Istnieją biblioteki pozwalające na łatwe tworzenie mocków. Jedną z nich jest EasyMock. EasyMock EasyMock jest to biblioteka, która daje możliwość tworzenia obiektów mock dla podanych interfejsów bądź klas. Obiekty mock potrafią symulować działanie rzeczywistych obiektów, tzn. dla zadanych parametrów metody zwracają odpowiednią wartość, można na przykład określić dozwoloną liczbę wywołań danej metody lub wymusić kolejność wywołań itp. Poniżej znajduje się wykaz często używanych funkcji biblioteki EasyMock. Aby korzystać z EasyMock należy zaimportować statycznie klasę EasyMock z pakietu org.easymock: import static org.easymock.easymock.*; Tworzenie atrapy obiektu: mock = createmock(<klasa/interfejs>.class); Obiekt mock posiada dwa stany: nagrywania i odgrywania. W stanie nagrywania należy dodać oczekiwane wywołania metod na obiekcie mock, wraz z dozwolonymi parametrami. Po przejściu w stan odgrywania obiekt mock może być używany tak samo jak rzeczywisty obiekt przez niego strona 4 / 7

zastępowany. W momencie, gdy interakcja z obiektem będzie odbiegać od oczekiwanej (ustawionej w fazie nagrywania), obiekt mock rzuci wyjątek/błąd typu AssertionError. Ustawianie oczekiwanych wywołań Dla metody nie zwracającej wartości: mock.metodaoczekiwana(<wartość parametru oczekiwana>); expectlastcall(). //operacje dodatkowe Dla metody zwracającej wartość: expect(mock.metodaoczekiwana(<wartość parametru oczekiwana>). Przejście ze stanu nagrywania do odtwarzania replay(mock); Weryfikacja interakcji z obiektem verify(mock); Określenie liczby wywołań expect(mock.metoda()).times(3); //dokładnie 3 wywołania expect(mock.metoda()).times(1, 3); //od 1 do 3 wywołań expect(mock.metoda()).anytimes(); //dowolna liczba wywołań expect(mock.metoda()).atleastonce();//przynajmniej jedno wywołanie Określenie wartości zwracanej expect(mock.metoda()).andreturn(<wartość>); Rzucanie wyjątków expect(mock.metoda()).andthrow(new MyException()); Ściśle określona kolejność wywołań Mock = createstrictmock(<klasa/interfejs>.class); Więcej funkcji można znaleźć w dokumentacji EasyMock: http://easymock.org/easymock3_0_documentation.html Zadania Poniżej znajduje się lista zadań do wykonania. Do każdego zadania przyporządkowany jest pakiet o nazwie io.testing.task<numer_zadania> w projekcie Mocks umieszczonym w archiwum Mock.zip. Zadanie 1 1. Uzupełnij kod w klasie Task1Starter strona 5 / 7

Utwórz obiekt mock w metodzie configuremock dla interfejsu IDataService Dodaj oczekiwanie na wywołanie metody connect, savedata z parametrem Moje dane, disconnect Przełącz obiekt mock w stan odgrywania Dodaj weryfikację interakcje z obiektem mock w metodzie playinteractions Uruchom program. Na konsoli nie powinny się pojawić żadne błędy interakcja z obiektem przebiegała zgodnie z oczekiwaniami. 2. Zmień przebieg interakcji z obiektem mock w metodzie playinteractions poprzez wywołanie metody savedata z innym parametrem, np. Nowe dane. Uruchom aplikację. Przejrzyj wygenerowany stack trace. Co jest przyczyną rzucenia błędu AssertionError? 3. Przywróć początkowy przebieg interakcji. Usuń metodę disconnect i uruchom program. Z jakiego powodu aplikacja przerwała swoje działanie? 4. Przywróć początkowy przebieg interakcji. Dodaj metodę connect po wywołaniu metody disconnect. Uruchom program. Jaki wystąpił błąd? 5. Obecnie nie jest weryfikowana kolejność wywołań metod obiektu mock. Przywróć stan początkowy i sprawdź czy przestawienie kolejności wywołania metod, np. poprzez zamianę connect z disconnect, ma wpływ na poprawność interakcji Zmień sposób tworzenia obiektu mock poprzez zamianę metody createmock na createstrictmock Uruchom aplikację. Jak zadziałała? Zadanie 2 W tej chwili jeżeli chcemy by metoda savedata była wywołana dokładnie dwa razy musimy dokładnie tyle wywołań tej metody wykonać podczas fazy nagrywania. Problemy z powyższym podejściem pojawią się w momencie, gdy będziemy chcieli np. by metoda ta została uruchomiona minimum 2 razy, ale nie więcej niż 5. W tym celu użyjemy specjalnych metod określających oczekiwaną ilość wywołań. Otwórz klasę Task2Starter Uruchom program. Dlaczego pojawia się błąd? Dodaj oczekiwanie by metoda connect była wywołana przynajmniej raz. Użyj konstrukcji expectlastcall().. Dodaj oczekiwanie by metoda savedata była wywołana 2 lub 3 razy bez względu na podaną wartość parametru. Wskazówka: użyj metody statycznej anyobject podając jako parametr klasę String. Dodaj oczekiwanie by metoda disconnect była wywołana przynajmniej raz. Uruchom program. Czy występują błędy? Zadanie 3 Do tej pory symulowane interakcje opierały się na wywoływaniu metod nie zwracających wartości. Przyszła kolej na dodanie wartości, które powinna zwracać dana funkcja. 1. Przejdź do klasy Task3Starter Uruchom program. Czy aplikacja uruchomiła się poprawnie? Jeśli nie to dlaczego? strona 6 / 7

Dodaj oczekiwanie by metoda getdata w pierwszym wywołaniu zwróciła pusty string Dodaj oczekiwanie by metoda getdata w drugim wywołaniu zwróciła string Moje dane Dodaj oczekiwanie by metoda getdata w trzecim wywołaniu zwróciła string Moje dane. Nowe dane Uruchom program i sprawdź co pojawia się na konsoli? 2. W interfejsie IDataService pojawiła się metoda countlength obliczająca liczbę znaków podanego parametru Odkomentuj interakcje w metodzie playinteractions Uruchom program. Co się dzieje? Dodaj oczekiwania dla metody countlength dla parametrów wyraz i dwa słowa ustawiając wartości zwracane na 5 i 9 Uruchom aplikacje. Co pojawiło się na konsoli? 3. Może się okazać, że podczas połączenia z prawdziwym obiektem DataService wystąpi błąd połączenia. W tym zadaniu zasymulujemy pojawienie się wyjątku ConnectException w obiekcie mock. Odkomentuj słowo kluczowe throws w interfejsie IDataService Dodaj oczekiwanie rzucania throws wyjątku przez metodę connect. Pamiętaj by zachować odpowiednią kolejność wywołania metod andthrows i atleastonce. Wywołanie connect powinno się znaleźć w klauzuli try/catch, mimo iż tak naprawdę w fazie nagrywania wyjątek ConnectException nie zostanie nigdy wygenerowany. W przypadku metody zwracającej wartość nie byłoby konieczności dodawania tej klauzuli. Dodaj klauzulę try/catch w metodzie playinteractions Uruchom aplikację. Czy wyjątek został wygenerowany? Zadanie 4 Obiekty typu mock najczęściej używa się w kontekście testowania jednostkowego. Spróbujemy teraz zastosować obiekt mock przy pisaniu testów dla klasy ServiceFacade, która wykorzystuje pewien serwis implementujący interfejs IDataService. Zamiast dostarczać obiektowi klasy ServiceFacade prawdziwy obiekt komunikujący się z istniejącym serwerem, dostanie on obiekt mock. Otwórz klasę ServiceFacade. W konstruktorze wymaga ona podania obiektu typu IDataService. Przeanalizuj kod dwóch metod. Otwórz klasę ServiceFacadeTest. Jest to klasa testowa dla klasy ServiceFacade. Posiada 3 metody testujące (do zaimplementowania) i jedną metodę setupbefore wywoływaną za każdym razem przed wykonaniem danego testu. Napisz metodę testową testreaddata. Najpierw skonfiguruj obiekt mock, następnie przełącz go w stan odtwarzania. Dodaj asercję JUnit sprawdzającą poprawność pobranych danych. Zweryfikuj obiekt mock. Napisz metodę testową teststoredata, podobnie jak poprzednią Doimplementuj metodę testreaddatawithexception, tak by zasymulować problem z połączeniem do serwera strona 7 / 7