• Co testować? 55 Stosowanie plików zawierających dane testowe W przypadku zestawów testów wymagających dużej ilości danych wejściowych można rozważyć ich umieszczenie (być może wraz z oczekiwanymi wynikami) w osobnych plikach wczytywanych przez testy jednostkowe. Implementacja takiego rozwiązania nie jest skomplikowana i niekoniecznie musi od razu wymagać zastosowania języka XML1. Poniżej przedstawio-na została wersja testu TestLargest, która wczytuje wszystkie testy z pliku. import junit.framework.*; import java.io.*; import java.util.ArrayList; import java.util.StringTokenizer; public class TestLargestDataFile extends TestCase { public TestLargestDataFile(String name) { super(name); } /* Wykonuje testy zapisane w pliku testdata.txt (nie testuje * przypadku wyjątku). Wyrzuca wyjątek w przypadku, * gdy któraś operacja wejścia i wyjścia zakończy się błędem. */ public void testFromFile() throws Exception { String line; BufferedReader rdr = new BufferedReader( new FileReader( "testdata.txt")); while ((line = rdr.readLine()) != null) { if (line.startsWith("#")) { // Ignoruje komentarz continue; } StringTokenizer st = new StringTokenizer(line); if (!st.hasMoreTokens()) { continue; // Pusty wiersz } // Pobiera spodziewany wynik String val = st.nextToken(); int expected = Integer.valueOf(val).intValue(); 1 To jest oczywiście żart, przecież zastosowanie języka XML jest obligatoryjne we wszystkich współczesnych projektach? 56 JUnit. Pragmatyczne testy jednostkowe w Javie // Oraz argumenty dla testowanej metody ArrayList argument_list = new ArrayList(); while (st.hasMoreTokens()) { argument_list.add(Integer.valueOf( st.nextToken())); } // Zamienia listę obiektów w tablicę typu podstawowego int[] arguments = new int[argument_list.size()]; for (int i=0; i < argument_list.size(); i++) { arguments[i] = ((Integer)argument_list. get(i)).intValue(); } // Wykonuje asercję assertEquals(expected, Largest.largest(arguments)); } } } TestLargestDataFile.java Plik danych testowych ma bardzo prosty format — każdy wiersz zawiera zbiór wartości. Pierwsza z nich jest oczekiwanym wynikiem, a pozostałe ar-gumentami testowanej metody. Dodatkowo zastosowanie znaku # na po-czątku wiersza umożliwia wprowadzanie komentarzy. A oto przykład zawartości takiego pliku: # # Proste testy: # 9 7 8 9 9 9 8 7 9 9 8 9 # # Testy z użyciem wartości ujemnych: # -7 -7 -8 -9 -7 -8 -7 -8 -7 -9 -7 -8 # # Testy mieszane: # 7 -9 -7 -8 7 6 4 9 -1 0 9 -7 4 # # Warunki brzegowe: # 1 1 0 0 2147483647 2147483647 testdata.txt -2147483648 -2147483648 Rozdział 4. • Co testować? 57 W przypadku kilku testów — jak choćby w powyższym przykładzie — wysiłek włożony w opracowanie odpowiedniego rozwiązania nie zwróci się. Jednak w przypadku zaawansowanej aplikacji wymagającej przeprowadzenia setek takich testów rozwiązanie wykorzystujące pliki danych na pewno warte jest zainteresowania. Należy przy tym pamiętać, że dane testowe — obojętnie, czy umieszczone bezpośrednio w kodzie, czy w pliku danych testowych — same mogą być niepoprawne. Doświadczenie podpowiada nawet, że prawdopodobieństwo tego, iż dane testowe są nieprawidłowe, jest większe niż tego, że testowany kod jest niepoprawny. Zwłaszcza jeśli dane testowe zostały przygotowane drogą ręcznych obliczeń lub uzyskane z systemu, który zastępujemy naszym oprogramowaniem (ponieważ jego nowe możliwości mogą mieć wpływ na uzyskiwane wyniki). Jeśli wyniki testów są niepomyślne, warto najpierw sprawdzić kilka razy poprawność danych testowych, zanim zabierzemy się do poszukiwania błędu w kodzie. Przedstawiony powyżej kod nie umożliwia testowania wyjątków. Zastanów się, w jaki sposób zaimplementować taką możliwość. Wybierz taki sposób testowania, który pozwoli najłatwiej sprawdzić, czy metoda działa poprawnie. Warunki brzegowe W przykładzie z wyszukiwaniem największego elementu listy udało nam się zidentyfikować szereg warunków brzegowych: gdy największy element znajdował się na końcu listy, gdy lista zawierała wartość ujemną, gdy lista była pusta i tak dalej. Identyfikacja warunków brzegowych jest jednym z najwartościowszych aspektów testowania, ponieważ pozwala wykryć i przetestować obszary, w których prawdopodobieństwo niepoprawnego działania kodu jest największe. Typowe warunki brzegowe powstają na skutek: 58 JUnit. Pragmatyczne testy jednostkowe w Javie t wprowadzenia całkowicie błędnych lub niespójnych danych wejściowych, na przykład łańcucha "!*W:X\&Gi/w~>g/h#WQ@"
|