testowanie klasy operującej na ułamkach

0

Witam,

Czytam ostatnio 2 książki: "Inżynieria oprogramowania w ujęciu obiektowym" oraz "JUnit in Action". Doszedłem do rozdziału 11. pierwszej książki który mówi o testowaniu. Jako, że ładnie wiąże się to z drugą książką postanowiłem wypróbować w praktyce to o czym czytam. Wymyśliłem sobie, że napiszę i przetestuję jednostkowo klasę do operacji na ułamkach. Piszę w tym dziale, gdyż poradziłem sobie z implementacją (Java) a mam problemy z testowaniem. Z konstruktorem klasy mi jeszcze jakoś poszło. Konstruktor odpowiada za ew. upraszczanie ułamka, redukcję minusów czy przeniesienie minusa z mianownika do licznika a takze za sprawdzenie czy ulamek moze byc utworzony (dzielenie przez 0). Pisząc testy dla konstruktora uzylem testów strukturalnych, czyli zidentyfikowalem wszystkie ścieżki ktorymi może podązyc egzekucja programu i dla każdej z nich napisalem 1 test.

Problem pojawił się w testowaniu operacji dodawania ulamkow. Zalozylem sobie, że jesli licznik lub mianownik wynikowego ulamka po dodaniu (i po ew. skroceniu) nie miesci sie w granicach int to rzuce wyjatek. Testując dodawanie chcialbym podejsc do tego od strony TDD (tak, wiem, że powinienem zaczać od testow ale teraz zakladam, że nie widzę implementacji). A wiec pytanie brzmi: jakiego podejscia uzyć aby wlasciwie przetestowac dodawanie ulamkow i nie skonczyc z powiedzmy 30 testami? Czy inaczej, jak dobrac zestaw danych testowych (zakladając ze nie widzimy implementacji) aby mieć największa pewnosc, ze metoda dodawania ulamkow zostala zaimplementowana poprawnie?

pozdrawiam

0

Ogólnie trzeba pomyśleć co użytkownik może wstawić w taki ułamek. Nie znam definicji metod, które chcesz testować ale można np. zrobić test czy metody łykają błędne dane(tekstowe, zmiennoprzecinkowe itp.). Następnie trzeba przetestować inne przypadki - nie wiem jak tworzysz taki ułamek ale trzeba sprawdzić co się dostanie w przypadku podania dodatnich lub ujemnych wartości w różnych kombinacjach. Na koniec możesz zrobić testy na overflow - wiesz jaki jest max liczb 32 i 64 bitowych - piszesz testy które dadzą wyniki w granicach.

Trzeba pamiętać by testować działanie pożądane i niepożądane - czyli jeśli klasa rzuca wyjątkiem to trzeba przetestować czy nim rzuci. Co do ilości testów to czy klasa ma 10 czy 30 to powinno zależeć od kategorii możliwych wywołań. Nie ma sensu pisać 30 testów sprawdzających to samo, każdy test powinien mieć jakiś powód i przyczynę, musi dawać odpowiedź na coś, na co inne testy nie dają.

Gdybyś dał jakiś kod(deklaracje funkcji), to wtedy można podyskutować jak ugryźć ten temat na czymś namacalnym.

0

Wbrew pozorom nie trzeba pisać wielu testów. Wystarczy, że:

  1. wyznaczysz wartości graniczne dla każdego parametru.
  2. dla każdej kombinacji wartości określisz oczekiwany wynik testów z obu stron granicy.
  3. Napiszesz po jednym teście na każdy z oczekiwanych wyników.

Jeżeli dla danej metody masz w ten sposób dużo testów oznacza, to tylko, że metoda ma za dużo odpowiedzialności i należy ją podzielić. Przy czym najpierw zaimplementuj ją tak by przeszła testy, a dopiero później podziel ją na mniejsze metody.

0

Dzięki za odpowiedzi. co do poprawosci danych to sie nie martwie bo Java sie nie skompiluje jak typ danych nie bedzie odpowiadał sygnaturze funkcji. moze rzeczywiscie bedzie latwiej na przykladzie. załóżmy ze konstruktor wyglada tak:

public Fraction(int licznik, int mianownik) throws ArithmeticException;

a metoda dodająca ulamki tak:

public Fraction add(Fraction f) throws ArithmeticException;

Jak pisałem, chciałbym skupić się na testowaniu dodawania a nie konstruktora. Przykładowe wywołanie metody wygląda więc nastepująco:

Fraction f1 = new Fraction(1,2);
Fraction f2 = new Fraction(1,4);
Fraction result = f1.add(f2);

Moge chyba załozyć, że argument przekazany do funkcji jest albo null'em (mam już ten test) albo poprawnym ułamkiem (w przeciwnym razie konstruktor rzuci wyjątek). Tak samo ułamek na którym wywoływana jest metoda, musi być poprawny bo inaczej albo konstruktor rzuci wyjątek (ArithmeticException) albo Java nie pozwoli na wywołanie metody add (NullPointerException). W testowaniu chciałbym sie wiec skupić nie tyle na poprawnosci danych, co na tym jak te dane na siebie wpływają. Czyli tak jak pisałem w pierwszym poście, jak dobrać dane zeby najlepiej przetestować te metodę. Moglbym zalozyc, że pierwszy ulamek moze byc ujemny, rowny 0 lub dodatni, tak samo drugi ale kombinacja dowolnie wybranych wartosci z tych przedziałów nie bylaby w mojej ocenie w pełni odpowiednim podejściem, bo nie gwarantuje, że przetestowane zostanie np. ustalanie wspolnego mianownika czy wartości skrajne (przekroczenie najwiekszego, najmniejszego ulamka ktory mozna przedstawic w zakresie int).
Powiedzmy jeden test to bedzie:
(MAX_INT-1)/MAX_INT + 2/MAX_INT Powinien on rzucić wyjątek. Kolejny:
1/MAX_INT + 1/(MAX_INT-1) Rownież wyjatek, bo wynikowa liczba będzie zbyt mała. A co z testem ktory np. mogłby (a nie powinien) rzucić wyjątek próbując ustalić wspólny mianownik ale potem po dodaniu i skroceniu mianownik miesci sie juz w zakresie int? Po prostu recznie mam znalezc taki przypadek? I kazdy kolejny ktory przyjdzie mi do glowy na podstawie tego co może się wydarzyć?

0

Daj klasę jakiemuś programiście i powiedz by się pobawił w wredny sposób, bez patrzenia na kod. Lub inaczej: pokaż mu interfejs i niech napisze wredny kod. Na pewno coś się sypnie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0