Diversity w polskim IT
Ng Wai Foong
Ng Wai FoongAI Engineer @ YOOZOO GAMES

Jak napisać testy automatyczne w Javie

Sprawdź, jak skutecznie krok po kroku napisać test automatyczny w Javie i ułatwić sobie pracę.
28.07.20215 min
Jak napisać testy automatyczne w Javie

W artykule tym zajmiemy się pisaniem skryptów dla automatyzacji testów w Javie. Technika ta polega na wykorzystaniu odpowiednich narzędzi do wykonania testów na każdym commicie i po aktualizacji związanej z jakimś błędem. 

Automatyzacja testów pomaga w zwiększeniu wydajności i dokładności Twojego systemu. Poza tym zrzuca to z Twoim barków większość żmudnej pracy manualnej, którą musisz wykonać, aby debugować lub testować swoją aplikację. 

Tutorial ten skupia się na JUnit5, dojrzałym frameworku do testów, który składa się z kilku modułów pochodzących z 3 różnych podprojektów:

  • Platforma JUnit: fundament do uruchamiania frameworków testowych na JVM. Zapewnia obsługę dla większości popularnych IDE (IntelliJ IDEA, Eclipse, NetBeans, and Visual Studio Code) i narzędzi do budowania (Gradle, Maven, and Ant).
  • JUnit Jupiter: nowy model programowania dla testów automatycznych w JUnit 5
  • JUnit Vintage: kompatybilny wstecznie silnik testowy, który obsługuje testy JUnit3 oraz JUnit 4.


Przejdźmy do następnej sekcji — zaczniemy pisać testy w Javie. 

Pisanie skryptów testowych

Upewnij się, że Twoja lokalna maszyna działa z JDK8 lub nowszymi wersjami. Stwórz nowy plik Javy i nazwij go SimpleTest.java.


Importowanie

Po pierwsze musimy zaimportować kilka głównych modułów JUnit Jupiter do pliku Java. Najprostszy przypadek testowy wymaga następujących podstawowych modułów: 

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;


Adnotacja

Następnie musisz umieścić adnotację swojej funkcji testowej z Test i wywołać wymaganą asercję, która znajduje się wewnątrz. 

Na przykład: 

@Test
void singleAssertion() {
    assertEquals(2, 1 + 1);
}


Funkcje z adnotacją Test zostaną wywołane, gdy uruchomisz swój test. 


Asercje

Poza assertEquals, mamy jeszcze wiele funkcji assert, których możesz użyć w swoim teście. Są to: 

  • assertNotEquals
  • assertNull
  • assertNotNull
  • assertTimeout
  • assertTrue
  • assertAll


Kompletna lista asercji znajduje się tutaj. Jedną z najbardziej użytecznych asercji jest assertAll — pomaga to w grupowaniu ich wszystkich*

@Test
void groupedAssertions() {
    assertAll("names",
        () -> assertEquals("Jane", "John"),
        () -> assertEquals("Doe", "Doe")
    );
}


Oto kompletny kod Twojego pierwszego testu:

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

class MyFirstJUnitJupiterTests {
    @Test
    void runningTest() {
        assertEquals(2, 1 + 1);
    }
}


Wyświetlanie nazwy 

Niestandardowe nazwy w raporcie testowym można wyświetlać za pomocą modułu DisplayName. Na wejście możemy podać ciąg znaków zawierający znaki alfanumeryczne, znaki specjalne, a nawet emoji: 

@Test
@DisplayName("Test function")
void singleAssertion() {
    assertEquals(2, 1 + 1);
}


Init oraz teardown

Jeżeli chcemy wykonać pewne funkcje przed lub po testach, możemy użyć adnotacji:

  • BeforeAll
  • BeforeEach
  • AfterAll
  • AfterEach


Spójrz na poniższy przykład — ilustruje on wszystkie adnotacje: 

@BeforeAll
static void initAll() {
}
@BeforeEach
void init() {
}
@AfterEach
void tearDown() {
}
@AfterAll
static void tearDownAll() {
}


Wyłącz/włącz test

Wyłączanie testu jest bardzo proste — wystarczy dodać adnotację Disable do metody. Na przykład: 

@Test
@Disabled("Disable this test")
void skippedTest() {
}


Dodatkowo można wyłączyć test w określonych warunkach. Powiedzmy, że chcesz wyłączyć test w na Windowsie. Powinieneś wykorzystać adnotację DisableOnOs, która akceptuje enum OS na górze funkcji. 

@Test
@DisabledOnOs(OS.WINDOWS)
void notOnWindows() {
}


Kompletną listę wszystkich warunków możesz zobaczyć tutaj. Pomijając tę kwestię możesz w prosty sposób włączyć test w oparciu o to, czy spełnia on niestandardowy warunek. Dodaj po prostu EnableIf na górze funkcji testowej i przekaż ją w argumencie string, który jest reprezentacją nazwy Twojego niestandardowego warunku:

@Test
@EnabledIf("customCondition")
void enabled() {        
}
boolean customCondition() {
    return true;
}


Testy sparametryzowane

JUnit5 obsługuje również sparametryzowane testy dzięki adnotacji ParameterizedTest. Następujący przykład ilustruje to, jak możesz tworzyć test sprawdzający, czy wartość wejściowa jest dodatnia: 

@ParameterizedTest
@ValueSource(ints = { -2, -1, 1, 2 })
void if_it_is_positive(int num) {
    assertTrue(num > 0);
}


W przeciwieństwie do adnotacji Test trzeba tutaj dostarczyć odpowiednie ValueSource, które reprezentuje wszystkie parametry wejściowe w funkcji testowej. 

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;

import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.api.condition.OS;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class SimpleTest{
    @BeforeAll
    static void initAll() {
    }

    @BeforeEach
    void init() {
    }

    @Test
    @DisplayName("Test function")
    void singleAssertion() {
        assertEquals(2, 1 + 1);
        assertTrue(1 < 2);
    }

    @Test
    void groupedAssertions() {
        assertAll("names",
            () -> assertEquals("Jane", "John"),
            () -> assertEquals("Doe", "Doe")
        );
    }

    @AfterEach
    void tearDown() {
    }

    @AfterAll
    static void tearDownAll() {
    }

    @Test
    @Disabled("Disable this test")
    void skippedTest() {
    }

    @Test
    @DisabledOnOs(OS.WINDOWS)
    void notOnWindows() {
    }

    @Test
    @EnabledIf("customCondition")
    void enabled() {
        
    }

    boolean customCondition() {
        return true;
    }

    @ParameterizedTest
    @ValueSource(ints = { -2, -1, 1, 2 })
    void if_it_is_positive(int num) {
        assertTrue(num > 0);
    }
}

Uruchamianie testu 

Większość popularnych IDE została już zintegrowana z JUnit jako część tego systemu. Jeśli masz jakieś problemy z uruchomieniem testu, przyjrzyj się następującym projektom przykładowym:  

Narzędzie do uruchamiania konsoli

W tym tutorialu wykorzystamy oddzielne narzędzie do uruchamiania konsoli. Użyjemy tutaj wersji 1.7.1 pliku jar, dzięki któremu uruchomimy testy. Pobierz po prostu odpowiedni plik jar na swoją lokalną maszynę. 


Budowanie klasy Javy

Teraz czas by stworzyć nowy folder o nazwie 'out' tam, gdzie pracujemy. Uruchom następującą komendę w terminalu, by zbudować klasę z testami.

javac -d out -cp junit-platform-console-standalone-1.7.1.jar out/SimpleTest.java


Nowy plik klasy Javy o nazwie SimpleTest.class zostanie utworzony w folderze out. Gdyby gdzieś pojawił się błąd, to oznacza to, że Twój plik Javy zawiera błędy. 


Uruchamianie testu

Uruchom następującą komendę, aby rozpocząć testowanie Twojej klasy Javy, gdy już z powodzeniem ukończysz jej budowanie: 

java -jar junit-platform-console-standalone-1.7.1.jar --class-path out --scan-class-path


Komenda ta przeskanuje wszystkie klasy Javy wewnątrz folderu out i uruchomi odpowiednie testy. Tak to powinno wyglądać w konsoli:


Obraz należy do autora

Podsumowanie

Podsumujmy to, czego się dzisiaj nauczyliśmy. Tutorial ten zaczął się szybkim wytłumaczeniem koncepcji testów automatycznych i podstaw stojących za JUnit 5. 

Następnie wytłumaczyliśmy sobie, w jaki sposób pisać testy przy użyciu JUnit Jupiter. Dotyczyło to podstawowych asercji, ale nauczyliśmy się też o parametryzowaniu testów.  

Później przyjrzeliśmy się budowaniu plików testowych klas Javy i uruchamianiu testów bezpośrednio przez oddzielne narzędzie do uruchamiania konsoli. 

Dziękuję za uwagę!

*Pomimo tego tworzenie wielu asercji w pojedynczym teście to nie jest najlepsza praktyka


Oryginał tekstu w języku angielskim możesz przeczytać tutaj

<p>Loading...</p>