środa, 16 maja 2012

Testowanie z JUnit w Eclipse

Wstęp.
Jeszcze nie pracuję, ale wydaje się, że w dzisiejszych czasach, w codziennej pracy, bez testów ani rusz. Swoją drogą, testowanie też przyda się w naszych amatorskich projektach. W tym wpisie chciałbym pokazać, że tworzenie prostych testów jednostkowych jest bajecznie proste. Zdziwiłem się, że dosłownie znajomość paru instrukcji pozwala tworzyć i uruchamiać nasze testy. Więc, jeśli chodzi o próg wejścia, to wydaje się, że jest niesamowicie niski, ale może to tylko złudne uczucie.

Zaczynamy! - Klasa którą będziemy testować.

Tworzymy javowy projekt w Eclipse i naszą klasę, żadna nowość. Przykład powinien być na tyle prosty, aby nie zaciemnić istoty tego, czego chcemy się nauczyć. Niech to będzie klasa wykonująca proste obliczenia matematyczne.

package com.blogspot.pgoralik.junit;

public class Calculator {
    public double sum(double addend1, double addend2) {
        return addend1 - addend2; // !
    }
 
    public double divide(double dividend, double divisor) {
        double result = dividend/divisor;
  
        if(Double.isInfinite(result))
             throw new IllegalArgumentException("Division by 0");
  
        return result;
    }
 
    public static void main(String[] args) {
        // Kod produkcyjny - bardzo ważne obliczenia!
        Calculator calc = new Calculator();
        double a = calc.divide(6.0, 2.0),
        result = calc.sum(a, 5.0);
    }
}
Jak widać wkradł się błąd, zamiast sumy wykonywane jest odejmowanie. W kodzie wykonujemy pewne obliczenia, które są obarczone tym błędem, wynik obliczeń jest błędny, jeżeli będziemy go wykorzystywać dalej, będzie propagował błędy i mamy problem, a błąd może się ujawnić w zupełnie innym miejscu.

Podstawowe wiadomości.

Mamy kilka podstawowych adnotacji do oznaczania metod:
  • @Before - metoda zostanie wywołana przed każdym testem (wywołaniem metody z @Test), służy do inicjalizacji np. wspólnych obiektów, których będziemy używać w metodach testujących.
  • @After - wywoływana na końcu, służy do sprzątania, zwolnienia jakiś zasobów itp.
  • @Test - tą odnotacją oznacza się metody testujące.
  • @Test(expected = Exception.class) - sprawdza czy metoda rzuciła dany wyjątek. Jeśli nie rzuciła to nie przeszliśmy testu.

Asercja sprawdza poprawność działania, mamy tego trochę, sporo przeładowanych funkcji (zobacz). Z ważniejszych to będą zapewne:
  • assertEquals
  • assertTrue
  • assertFalse
Klasa testująca.

Dobrze było by sobie oddzielić kod produkcyjny od testów, możemy utworzyć sobie obok katalogu source nowy katalog, np. tests. Wchodzimy w ustawienia projektu, wybieramy Java Build Path, następnie Add folder i Create new folder. Podajemy nazwę folderu i gotowe.

Aby utworzyć klasę z testami dla naszej klasy, klikamy prawym przyciskiem myszy na Calculator.java w drzewie z hierarchią plików projektu i wybieramy New->JUnit Test Case. Pamiętajmy aby zmienić Source folder na ten nowo utworzony. Możemy poustawiać różne opcje, wybrać metody do których ma nam Eclipse automatycznie wygenerować metody testujące. Zaznaczmy może tylko metodę sum.

Dopiszmy teraz do już wygenerowanego kodu nasz kod:
package com.blogspot.pgoralik.junit;

import static org.junit.Assert.*;
import org.junit.*;

public class CalculatorTest {
    private Calculator calc;
    private double zero, two, nine;
 
    @Before 
    public void setUp() {
        calc = new Calculator();
        zero = 0.0;
        two = 2.0;
        nine = 9.0;
    }

    @Test
    public void testSum() {
        // (spodziewany wynik, aktualny wynik, dokładność bo operujemy na double)
        assertEquals(11.0, calc.sum(two, nine), 0.000001);
    }
 
    @Test
    public void testDivision() {
        assertEquals(4.5, calc.divide(nine, two), 0.000001);
    }
 
    @Test(expected = IllegalArgumentException.class)
    public void divideBy0() {
        calc.divide(nine, zero);
    }

}
W tym przypadku chciałem pokazać użycie adnotacji Before, wygląda to trochę sztucznie, ale jeśli te dane testowe nie były by typami prostymi, a obiektami, które potrzebują do konstrukcji trochę wysiłku, to takie podejście jest przydatne. Testy uruchamiamy wybierając Run->Run As->JUnit Test. Jak widzimy, metoda testSum nie przechodzi testu. Spodziewaliśmy się 11.0, a otrzymujemy -7.0.


Jeżeli poprawimy błąd w metodzie Calculator.sum() to wszystkie testy powinny przejść, dostajemy zielone światło i wiemy, że wszystko działa jak należy.


Słowo na koniec.

To są podstawy - ja też się tego dopiero uczę. Jeśli chcesz wiedzieć więcej zaglądnij w inne źródła, na pewno godna polecenia jest strona http://junit.sourceforge.net/.

Brak komentarzy:

Prześlij komentarz