Testowanie II Cel zajęć Celem zajęć jest zapoznanie studentów z oceną jakości testów przy wykorzystaniu metryk pokrycia kodu testami (ang. code coverage). Pokrycie kodu testami 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ść 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: a) 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(); następujący test gwarantuje 100% pokrycia wyrażeń: public void testadditems() { assertequals(3, someobject.additems(new ArrayList())); b) 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(items); return list.size(); następujący test gwarantuje 50% pokrycia decyzji, gdyż warunek w instrukcji warunkowej przyjmuje jedynie wartość true: public void testadditems() { assertequals(1, someobject.additem(new Object()));
c) pokrycie warunków (ang. condition coverage) Podobobne do pokrycia decyzji, bierze jednak pod uwagę wartośći jakie przyjmują podwyrażenia logiczne. d) pokrycie ścieżek (ang. path coverage) Weryfikuje, czy każda możliwa ścieżka wykonania 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; assertequals(2, object.calculate()); dopiero następujący test gwarantuje 100% pokrycia ścieżek: public void testcalculate() { object.a = 2; assertequals(2, object.calculate()); object.a = 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()); e) pokrycie metod (ang. methid coverage) Sprawdza, czy wszystkie dostępne metody zostały wywołane podczas testowania. f) pokrycie klas (ang. class coverage) Sprawdza, czy wszystkie klasy zostały zainicjalizowane chociaż raz.
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 jest kilka sytuacji pokazujących, że takie podejście może być czasem mylące: a) 100% pokrycia nie gwarantuje jakości! public List addobject(list list, Object o) { list.add(o); return list; następujący test gwarantuje 100% pokrycia wyrażeń, decyzji, warunków, metod, klass, ale nic tak naprawdę nie testuje, bo nie ma w nim żadnej instrukcji assert*: 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, klass, ale źle dobrane dane wejściowe powodują, że test nie wykrywa błędu: public void testadd() { assertequals(4, object.multiply(2, 2)); b) Czasami 100% pokrycie nie może być osiągnięte! public List<String> addobject(list<string> list, String newname) { for (String name : list) { System.out.println(name); System.out.println("-----------"); list.add(newname); return list; nie możliwe jest stworzenie testu ze 100% pokryciem ścieżek. c) Co z testowaniem pętli? Czy wystarczy jeśli kod pętli został wykonany tylko raz?
Badanie pokrycia kodu przy pomocy narzędzia EclEmma EclEmma to wtyczka do Eclipse'a pozwalająca nam sprawdzić pokrycie kodu testami. 1. Zaimportuj projekt z pliku CodeCoverage4Students.zip (File->Import->Existing Project Into Workspace). 2. W widoku Package Explorer znajdź plik BootsTest.java, kliknij na nim PPM i wybierz opcję Coverage As -> JUnit Test: 3. Zostanie uruchomiony test. W widoku JUnit widzimy, że test przeszedł, co jednak z pokryciek kodu testami? W widoku Coverage (jeśli widok nie pojawił się automatycznie możemy go otworzyć przez Window->Show View->Other...) widzimy statystyki. Dodatkowo gdy otworzymy nasze klasy zauważym, że nasz kod został oznaczony kolorami. I tak: kolor zielony onacza, że linia została całkowicie pokryta kolor żółty oznacza, że linia została częściowo pokryta kolor czerwony oznacza, że linia w ogóle nie została wykonana W naszym przykładzie testujemy klasę Boots, a dokładniej jej metodę printsummary, która jest zdefiniowana w klasie Item. Otwórzmy zatem klasę Item i spójrzy na metodę printsummary: public String printsummary() { String summary = ""; if (type == THIS_YEAR) { summary += "NEW!\n"; if (producername!= null && producername.length() > 0) { summary += "Producer: " + producername + "\n"; int totaldiscountamount = 0; for (Discount discount : currentdiscountslist) { totaldiscountamount += discount.getpercentage(); if (totaldiscountamount > 0) { if (totaldiscountamount > 30) { totaldiscountamount = 30; summary += "Discount: " + totaldiscountamount + "%\n"; summary += "Final Price: " + (price * (1 - (totaldiscountamount / 100))) + "\n"; summary += printdetails(); return summary; Możemy zauważyć, że nasz test nie przechodzi przez wszystkie linie kodu metody oraz nie sprawdza wszystkich wartości wyrażeń logicznych. Należałoby dopisać dodatkowe testy, tak aby pokrycie było jak największe.
Ćwiczenie Wyobraźmy sobie sytuację, że jesteśmy w trakcie pisania systemu dla sklepu interentowego zajmującego się sprzedażą sprzętu narciarskiego. Częśc systemu mamy już napisaną, brakuje nam jednak kilku testów. Naszym zadaniem będzie dopisanie testów dla istniejących klas, tak aby znaleźć istniejące błędy oraz aby pokrycie kody testami było jak największe. 1. Jeśli jeszcze twego wcześniej nie zrobiłeś to zaimportuj projekt z pliku CodeCoverage4Students.zip (File->Import->Existing Project Into Workspace). 2. Przejrzyj kod znajdujący się w katalogu src, a następnie napisz dla niego testy i sprawdź dla nich pokrycie kodu. Opis metod znajduje się w komentarzach JavaDoc. 3. Po napisaniu testów popraw znalezione błędy.