Prezentacja JUnit.

Wstęp

JUnit został stworzony przez dwójkę programistów - Ericha Gamma i Kenta Becka. Jest to narzędzie wspomagające pisanie i przeprowadzanie testów dla programów pisanych w Javie. Udostępnia on między innymi prosty interfejs graficzny, dzięki któremu możemy uruchamiać przygotowane testy. JUnit pozwala nam:

Instalacja

  1. Ściągamy najnowszą wersję JUnit ze strony www.junit.org.
  2. Rozpakowujemy ją do wybranego katalogu.
  3. Rozszerzamy zmienną systemową CLASSPATH o ścieżkę do pliku junit.jar z katalogu JUnit. (dla Windows polecenie set, export pod Linuksem)

Test Driven Development

JUnit został stworzony z myślą o programistach piszących programy zgodnie z metodologią Extreme Programming. Doświadczenie wielu programistów udowadnia, że w procesie powstawania oprogramowania bardzo dużą rolę odgrywają automatyczne testy. Przygotowanie testów dla gotowych aplikacji jest często trudne, jeśli nie nie możliwe. Jedną z praktyk programistycznych ułatwiających pisanie złożonych aplikacji jest właśnie Test Driven Development. Jej głównym założeniem jest zmiana podejścia do testów. W klasycznym podejściu najpierw tworzony jest kod, a następnie testy mające sprawdzić jego poprawne działanie. W TDD pisanie testów jest postawione na pierwszym miejscu.

W największym skrócie powstawanie kodu powinno wyglądać następująco:

  1. Piszemy test sprawdzający określoną funkcjonalność.
  2. Upewniamy się, czy przypadkiem nasz program już jej nie realizuje (uruchomione testy kończą sięw stani porażki).
  3. Piszemy jak najprostszy kod przechodzący pomyślnie powyższy test.
  4. Powtarzamy.

Dzięki JUnit pisanie i uruchamianie testów jest łatwe i wydajne. Organizacja testów w zestawy pozwala nam oddzielić często uruchamiane małe zestawy testów od przygotowanych wcześniej zestawów uruchamianych raz dziennie i testujących dużą część tworzonej aplikacji. Wygodny i prosty interfejs pozwala łatwo uruchamiać wybrane zestawy testów, nawet te napisane pół roku wcześniej.

Jak pisać testy?

Ten punkt nie odpowiada na pytanie "Kiedy pisać testy?". Częściowa odpowiedź na tak postawione pytanie znajduje się w poprzedniej części. Na potrzeby prezentacji wyłamujemy się jednak z tego schematu. Przypuśćmy, że stworzyliśmy prostą klasę Multiplier:

public class Multiplier {
  private int temp;

public int multiply(int a,int b) {
return a*b;
}

public int pow(int a,int n) {
while (n>0) {
temp *= a;
n--;
}
return temp;
}
}

Klasa ta udostępnia dosyć wąską funkcjonalność, pozwala pomnożyć przez siebie parę liczb całkowitych, oraz podnieść liczbę do określonej potęgi. Co zrobić, żeby sprawdzić, czy klasa spełnia swoją funkcjonalność? Po pierwsze tworzymy klasę dziedziczącą po klasie TestCase z pakietu JUnit:

import junit.framework.*;


public class MultiplierTest extends TestCase{


}

Klasa ta zawierała będzie:

Kolejnym krokiem jest zainicjowanie obiektów, które będziemy testowali. Oczywiści możemy zrobić to dopiero dopiero w metodach testujących, ale poniższy przykład zilustruje nam mechanizm pozwalający inicjalizować obiekty wykorzystywane w wielu testach:

  private Multiplier m;
  protected void setUp(){
    m = new Multiplier();
  }
 

Metoda setUp() uruchamiana jest przed każdym uruchomieniem testów z naszej klasy. Dzięki czemu możemy w niej umieścić kod, który inczej musielibyśmy wielokrotnie przepisywać w każdej z metod testujących. Następny krok, to właśnie napisanie metod testujących:

 public void testMultiply() {
   assertTrue(m.multiply(2,3) == 6 );
 }
   
 public void testPow(){
   assertEquals("2^4 = 16", 16, m.pow(2,4));
 }
 

Do sprawdzania warunków używamy udostępnianych przez JUnit metod assertTrue, assertEquals itp. Jako parametr możemy przekazać warunek logiczny, jak również obiekt klasy String. Jeśli test się nie powiedzie powyższy napis stanowił będzie jedną z informacji identyfikujących test, który nie przeszedł. Kolejnym krokiem jest utworzenie instancji tworzonej klasy uruchamiającej wybrany test:

new MultiplierTest("testMultiply");

Przekazywany parametr, jest jednocześnie nazwą identyfikującą test, oraz nazwą metody którą powyższy test wywoła. Przy uruchamianiu testów standartowo uruchamiana jest metoda runTest(), która domyślnie wyszukuje metodę o podanej nazwie i ją wywyołuje. Często stosowaną praktyką jest nadpisywanie tej metody. Taki mechanizm pozwala tworzyć testy uruchamiające np. kilka wybranych metod. Najłatwiejszą metodą nadpisywania tej metody jest stworzenie anonimowej klasy implementującej metodę runTest() w wybrany przez nas sposób.

  new MultiplierTest("test potęgowania") {
    protected void runTest(){ testPow(); }
  }

Jeśli chcemy uruchomić kilka testów jednocześnie, możemy utworzyć zestawu testów. Najprostszą metodą jest wywołanie konstruktora zestawu testów z nazwą naszej przekazaną jako parametr. Konstruktor ten automatycznie wydobędzie z naszej klasy wszyskie testy i dołączy je do tworzonego zestawu testów:

TestSuite suite= new TestSuite(MultiplierTest.class); 

Ostatnim krokiem, który chcemy wykonać jest uruchomienie zestawu testów. JUnit udostępnia mechanizm, który automatycznie uruchamia wybrane testy i przedstawia ich wyniki w czytelnej postaci. Po pierwsze musimy w naszej klasie zdefiniować metodę public static Test suite() . Poniższy przykład zilustruje również drugą metodę tworzenia zestawu testów:

public static Test suite(){


  TestSuite suite = new TestSuite();
  suite.addTest(
    new MultiplierTest() {
      protected void runTest(){ testPow();}
    }
  );
   
  Test test1 = new MultiplierTest(){
    protected void runTest() { testMultiply(); }
  };
 suite.addTest(test1);
 return suite;
}

Tak stworzony zestaw testów można już łatwo uruchomić korzystając z tekstowego lub jednego z graficznych narzędzi udostępnianych przez JUnit. Uruchamiamy je wpisując z linii poleceń: java junit.awtui.TestRunner lub java junit.swingui.TestRunner.

W polu Test class name wpisujemy nazwę klasy, zawierającej test, który chcemy uruchomić. Następnie klikamy przycisk Run. W polu results pojawi się podsumowanie wyników przeprowadzonego testu. W tym przypadku okazało się, że jedna z testowanych metod nie działa poprawnie. Po naniesieniu oczywistej poprawki:

 public int pow(int a,int n) {

   temp = 1;
   while (n>0) {
     temp *= a;
     n--;
   }
   return temp;
 }
 

Ponownie kompilujemy klasę multiplier, i uruchamiamy TestRunner'a:

Jeśli wszystkie testy zakończyły się powodzeniem TestRunner zasygnalizuje to zielonym kolorem paska stanu testów.

Więcej informacji

Dodatkowe informacje można znaleźć na poniższych stronach internetowych: