Szukaj…


Uwagi

Tworzenie lokalnych testów jednostkowych

Umieść tutaj swoje klasy testowe: /src/test/<pkg_name>/

Przykładowa klasa testowa

public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        int a=4, b=5, c;
        c = a + b;
        assertEquals(9, c); // This test passes
        assertEquals(10, c); //Test fails
    }
}

Awaria

public class ExampleUnitTest {
  ...
}

W klasie testowej możesz utworzyć kilka klas testowych i umieścić je w pakiecie testowym.

@Test
public void addition_isCorrect() {
   ...
}

Metoda testowa. W klasie testowej można utworzyć kilka metod testowych.

Zwróć uwagę na adnotację @Test .

Adnotacja Test informuje JUnit, że publiczna metoda void, do której jest dołączona, może być uruchomiona jako przypadek testowy.

Istnieje kilka innych przydatnych adnotacji, takich jak @Before , @After itp. Ta strona byłaby dobrym miejscem do rozpoczęcia.

assertEquals(9, c); // This test passes
assertEquals(10, c); //Test fails

Te metody należą do klasy Assert . Niektóre inne użyteczne metody to assertFalse() , assertNotNull() , assertTrue itp. Oto skomplikowane objaśnienie .


Informacje o adnotacjach dla testu JUnit:

@Test: Adnotacja testowa informuje JUnit, że publiczna metoda void, do której jest dołączona, może być uruchomiona jako przypadek testowy. Aby uruchomić metodę, JUnit najpierw konstruuje nową instancję klasy, a następnie wywołuje metodę z adnotacjami.

@Przed: Podczas pisania testów często zdarza się, że kilka testów wymaga podobnych obiektów utworzonych przed ich uruchomieniem. @Before adnotacji do publicznej metody void za pomocą @Before powoduje, że metoda ta zostanie uruchomiona przed metodą testową.

@After: Jeśli przydzielisz zasoby zewnętrzne w metodzie Przed, musisz je zwolnić po uruchomieniu testu. Adnotacja publicznej nieważnej metody za pomocą @After powoduje, że ta metoda jest uruchamiana po metodzie testowej. @After wszystkie metody @After będą działać, nawet jeśli metoda Before lub Test zgłosi wyjątek


Wskazówka Szybko twórz klasy testowe w Android Studio

  • Umieść kursor na nazwie klasy, dla której chcesz utworzyć klasę testową.
  • Naciśnij klawisze Alt + Enter (Windows).
  • Wybierz Utwórz test, naciśnij Return.
  • Wybierz metody, dla których chcesz utworzyć metody testowe, kliknij przycisk OK.
  • Wybierz katalog, w którym chcesz utworzyć klasę testową.
  • Skończyłeś, to co dostajesz, to twój pierwszy test.

Wskazówka Łatwo wykonuj testy w Android Studio

  • Kliknij test prawym przyciskiem myszy.
  • Wybierz Uruchom testy w ...
  • Wszystkie testy w pakiecie zostaną wykonane jednocześnie.

Przenoszenie logiki biznesowej z komponentów Android

Wiele wartości z lokalnych testów jednostkowych JVM pochodzi ze sposobu projektowania aplikacji. Musisz zaprojektować go w taki sposób, aby oddzielić logikę biznesową od komponentów Android. Oto przykład takiego sposobu wykorzystania wzorca Model-View-Presenter . Przećwiczmy to, wdrażając podstawowy ekran rejestracji, który przyjmuje tylko nazwę użytkownika i hasło. Nasza aplikacja na Androida odpowiada za sprawdzenie, czy podana przez użytkownika nazwa użytkownika nie jest pusta, a hasło ma co najmniej osiem znaków i co najmniej jedną cyfrę. Jeśli nazwa użytkownika / hasło są prawidłowe, wykonujemy nasze wywołanie interfejsu API, w przeciwnym razie wyświetlamy komunikat o błędzie.

Przykład, w którym logika biznesowa jest silnie sprzężona z komponentem Android.

public class LoginActivity extends Activity{
    ...
    private void onSubmitButtonClicked(){
        String username = findViewById(R.id.username).getText().toString();
        String password = findViewById(R.id.password).getText().toString();
        boolean isUsernameValid = username != null && username.trim().length() != 0;
        boolean isPasswordValid = password != null && password.trim().length() >= 8 && password.matches(".*\\d+.*");
        if(isUsernameValid && isPasswordValid){
            performSignUpApiCall(username, password);
        } else {
            displayInvalidCredentialsErrorMessage();
        }
    }
}

Przykład, w którym logika biznesowa jest oddzielona od komponentu Android.

Tutaj definiujemy w pojedynczej klasie LoginContract, która pomieści różne interakcje między naszymi różnymi klasami.

public interface LoginContract {
    public interface View {
        performSignUpApiCall(String username, String password);
        displayInvalidCredentialsErrorMessage();
    }
    public interface Presenter {
        void validateUserCredentials(String username, String password);
    }
}

Nasza LoginActivity jest w większości taka sama, z wyjątkiem tego, że usunęliśmy odpowiedzialność za sprawdzenie poprawności formularza rejestracji użytkownika (nasza logika biznesowa). LoginActivity będzie teraz polegać na naszym nowym LoginPresenter do przeprowadzania weryfikacji.

public class LoginActivity extends Activity implements LoginContract.View{
    private LoginContract.Presenter presenter;

    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            presenter = new LoginPresenter(this);
            ....
        }
        ...

        private void onSubmitButtonClicked(){
            String username = findViewById(R.id.username).getText().toString();
            String password = findViewById(R.id.password).getText().toString();
            presenter.validateUserCredentials(username, password);
    }
    ...
}

Teraz logika biznesowa będzie znajdować się w nowej klasie LoginPresenter.

public class LoginPresenter implements LoginContract.Presenter{
    private LoginContract.View view;

    public LoginPresenter(LoginContract.View view){
        this.view = view;
    }

    public void validateUserCredentials(String username, String password){
        boolean isUsernameValid = username != null && username.trim().length() != 0;
        boolean isPasswordValid = password != null && password.trim().length() >= 8 && password.matches(".*\\d+.*");
        if(isUsernameValid && isPasswordValid){
            view.performSignUpApiCall(username, password);
        } else {
            view.displayInvalidCredentialsErrorMessage();
        }
    }
}

A teraz możemy utworzyć lokalne testy jednostkowe JVM w stosunku do nowej klasy LoginPresenter.

public class LoginPresenterTest {

    @Mock
    LoginContract.View view;

    private LoginPresenter presenter;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        presenter = new LoginPresenter(view);
    }

    @Test
    public void test_validateUserCredentials_userDidNotEnterUsername_displayErrorMessage() throws Exception {
        String username = "";
        String password = "kingslayer1";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view). displayInvalidCredentialsErrorMessage();
    }

    @Test
    public void test_validateUserCredentials_userEnteredFourLettersAndOneDigitPassword_displayErrorMessage() throws Exception {
        String username = "Jaime Lanninster";
        String password = "king1";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view). displayInvalidCredentialsErrorMessage();
    }

    @Test
    public void test_validateUserCredentials_userEnteredNineLettersButNoDigitsPassword_displayErrorMessage() throws Exception {
        String username = "Jaime Lanninster";
        String password = "kingslayer";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view). displayInvalidCredentialsErrorMessage();
    }

    @Test
    public void test_validateUserCredentials_userEnteredNineLettersButOneDigitPassword_performApiCallToSignUpUser() throws Exception {
        String username = "Jaime Lanninster";
        String password = "kingslayer1";
        presenter.validateUserCredentials(username, password);
        Mockito.verify(view).performSignUpApiCall(username, password);
    }
}

Jak widać, kiedy wyodrębniliśmy naszą logikę biznesową z LoginActivity i umieściliśmy ją w LoginPresenter POJO . Możemy teraz tworzyć lokalne testy jednostkowe JVM w oparciu o naszą logikę biznesową.

Należy zauważyć, że z naszej zmiany w architekturze wiążą się różne inne konsekwencje, takie jak to, że jesteśmy bliscy przylgnięcia do każdej klasy mającej jedną odpowiedzialność, dodatkowe klasy itp. Są to tylko skutki uboczne sposobu, w jaki zdecydowałem się na wykonanie tego odsprzęganie za pomocą stylu MVP. MVP to tylko jeden ze sposobów, aby się tym zająć, ale istnieją inne alternatywy, na które warto spojrzeć, takie jak MVVM . Musisz tylko wybrać najlepszy system, który działa dla Ciebie.

Rozpoczęcie pracy z JUnit

Ustawiać

Aby rozpocząć testowanie jednostkowe projektu Android za pomocą JUnit, musisz dodać zależność JUnit do swojego projektu i musisz utworzyć testowy zestaw źródłowy, który będzie zawierał kod źródłowy dla testów jednostkowych. Projekty tworzone w Android Studio często zawierają już zależność JUnit i zestaw źródeł testowych

Dodaj następujący wiersz do pliku build.gradle modułu w zależnościach Closure :

testCompile 'junit:junit:4.12'

Klasy testowe JUnit znajdują się w specjalnym zestawie źródłowym o nazwie test . Jeśli ten zestaw źródeł nie istnieje, musisz samodzielnie utworzyć nowy folder. Struktura folderów domyślnego projektu Android Studio (na bazie Gradle) wygląda następująco:

<project-root-folder>
    /app (module root folder)
        /build
        /libs
        /src
            /main (source code)
            /test (unit test source code)
            /androidTest (instrumentation test source code)
        build.gradle (module gradle file)
    /build
    /gradle
    build.gradle (project gradle file)
    gradle.properties
    gradlew
    gradlew.bat
    local.properties
    settings.gradle (gradle settings)

Jeśli twój projekt nie ma folderu /app/src/test , musisz go utworzyć samodzielnie. W folderze test potrzebujesz również folderu java (utwórz go, jeśli nie istnieje). Folder Java w test zestawie źródłowym powinien zawierać tę samą strukturę pakietu, co main zestaw źródłowy.

Jeśli poprawnie skonfigurujesz, struktura projektu (w widoku Androida w Android Studio) powinna wyglądać następująco:

konfiguracja projektu

Uwaga: niekoniecznie musisz mieć androidTest źródłowy androidTest , ten zestaw źródłowy często znajduje się w projektach tworzonych przez Android Studio i jest tu zamieszczony w celach informacyjnych.


Pisanie testu

  1. Utwórz nową klasę w zestawie test .
    Kliknij prawym przyciskiem myszy zestaw testowy w widoku projektu i wybierz New > Java class .
    Najczęściej stosowanym wzorcem nazewnictwa jest użycie nazwy klasy, którą zamierzasz przetestować z dodanym Test . Zatem StringUtilities staje się StringUtilitiesTest .

  2. Dodaj adnotację @RunWith
    Adnotacja @RunWith jest potrzebna, aby JUnit uruchomił testy, które zdefiniujemy w naszej klasie testowej. Domyślnym programem uruchamiającym JUnit (dla JUnit 4) jest BlockJUnit4ClassRunner ale zamiast bezpośredniego uruchamiania bardziej wygodne jest użycie aliasu JUnit4 który jest skrótem dla domyślnego programu JUnit4 JUnit.

     @RunWith(JUnit4.class)
     public class StringUtilitiesTest {
     
     }
    
  3. Utwórz test
    Test jednostkowy jest w zasadzie tylko metodą, która w większości przypadków nie powinna zawieść, jeśli zostanie uruchomiona. Innymi słowy, nie powinien generować wyjątku. Wewnątrz metody testowej prawie zawsze znajdziesz twierdzenia, które sprawdzają, czy spełnione są określone warunki. Jeśli asercja się nie powiedzie, zgłasza wyjątek, który powoduje niepowodzenie metody / testu. Metoda testowa jest zawsze opatrzona adnotacją @Test . Bez tej adnotacji JUnit nie uruchomi automatycznie testu.

     @RunWith(JUnit4.class)
     public class StringUtilitiesTest {
    
         @Test
         public void addition_isCorrect() throws Exception {
             assertEquals("Hello JUnit", "Hello" + " " + "JUnit");
         }
     }
    

    Uwaga: w przeciwieństwie do standardowej metody testowania jednostek nazewniczych w metodzie Java często zawierają znaki podkreślenia.


Przeprowadzanie testu

  1. metoda
    Aby uruchomić pojedynczą metodę testową, możesz kliknąć metodę prawym przyciskiem myszy i kliknąć Run 'addition_isCorrect()' lub użyć skrótu klawiaturowego ctrl+shift+f10 . Przeprowadź pojedynczy test jednostkowy

    Jeśli wszystko jest poprawnie skonfigurowane, JUnit uruchomi metodę i powinieneś zobaczyć następujący interfejs w Android Studio:

    Interfejs testu jednostkowego Android Studio

  1. Klasa
    Możesz również uruchomić wszystkie testy zdefiniowane w jednej klasie, klikając prawym przyciskiem myszy klasę w widoku projektu i klikając opcję Run 'StringUtilitiesTest ' lub użyj skrótu klawiaturowego ctrl+shift+f10 jeśli wybrałeś klasę w widoku projektu.

  2. Pakiet (wszystko)
    Jeśli nie chcesz uruchamiać wszystkich testów zdefiniowanych w projekcie lub w pakiecie, możesz po prostu kliknąć pakiet prawym przyciskiem myszy i kliknąć Run ... tak, jakbyś uruchomił wszystkie testy zdefiniowane w jednej klasie.

Wyjątki

JUnit może być również używany do testowania, czy metoda zgłasza określony wyjątek dla danego wejścia.

W tym przykładzie przetestujemy, czy następująca metoda naprawdę zgłasza wyjątek, jeśli format boolowski (wejście) nie zostanie rozpoznany / nieznany:

public static boolean parseBoolean(@NonNull String raw) throws IllegalArgumentException{
    raw = raw.toLowerCase().trim();
    switch (raw) {
        case "t": case "yes": case "1": case "true":
            return true;
        case "f": case "no": case "0": case "false":
            return false;
        default:
            throw new IllegalArgumentException("Unknown boolean format: " + raw);
    }
}

Dodając expected parametr do adnotacji @Test , można zdefiniować, który wyjątek ma zostać zgłoszony. Test jednostkowy zakończy się niepowodzeniem, jeśli ten wyjątek nie wystąpi, i powiedzie się, jeśli wyjątek zostanie rzeczywiście zgłoszony:

@Test(expected = IllegalArgumentException.class)
public void parseBoolean_parsesInvalidFormat_throwsException(){
    StringUtilities.parseBoolean("Hello JUnit");
}

Działa to dobrze, jednak ogranicza cię do jednego przypadku testowego w ramach metody. Czasami możesz chcieć przetestować wiele przypadków w ramach jednej metody. Często stosowaną techniką w celu przezwyciężenia tego ograniczenia jest użycie bloków try-catch i metody Assert.fail() :

@Test
public void parseBoolean_parsesInvalidFormats_throwsException(){
    try {
        StringUtilities.parseBoolean("Hello!");
        fail("Expected IllegalArgumentException");
    } catch(IllegalArgumentException e){
    }

    try {
        StringUtilities.parseBoolean("JUnit!");
        fail("Expected IllegalArgumentException");
    } catch(IllegalArgumentException e){
    }
}

Uwaga: Niektóre osoby uważają za złą praktykę testowanie więcej niż jednego przypadku w teście jednostkowym.

Import statyczny

JUnit definiuje niektóre metody assertEquals , co najmniej jedna dla każdego typu pierwotnego i jedna dla Obiektów jest dostępna. Te metody są domyślnie niedostępne do wywołania i powinny być wywoływane w następujący sposób: Assert.assertEquals . Ponieważ jednak metody te są używane tak często, ludzie prawie zawsze używają importu statycznego, dzięki czemu można bezpośrednio użyć metody, tak jakby była częścią samej klasy.

Aby dodać import statyczny dla metody assertEquals , użyj następującej instrukcji importu:

import static org.junit.Assert.assertEquals;

Możesz również zaimportować statycznie wszystkie metody assert, w tym assertArrayEquals , assertNotNull i assertFalse itp., Używając następującego importu statycznego:

import static org.junit.Assert.*;

Bez importu statycznego:

@Test
public void addition_isCorrect(){
    Assert.assertEquals(4 , 2 + 2);
}

Ze statycznym importem:

@Test
public void addition_isCorrect(){
    assertEquals(4 , 2 + 2);
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow