Поиск…


замечания

Создание локальных модульных тестов

Поместите свои тестовые классы здесь: /src/test/<pkg_name>/

Пример тестового класса

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
    }
}

Сломать

public class ExampleUnitTest {
  ...
}

В тестовом классе вы можете создать несколько тестовых классов и поместить их в тестовый пакет.

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

Метод проверки, несколько тестовых методов могут быть созданы внутри тестового класса.

Обратите внимание на аннотацию @Test .

Аннотирование теста сообщает JUnit, что общедоступный метод void, к которому он присоединен, может быть запущен в качестве тестового примера.

Есть несколько других полезных аннотаций, таких как @Before , @After и т. Д. Эта страница будет хорошим местом для начала.

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

Эти методы являются членами класса Assert . Некоторые другие полезные методы: assertFalse() , assertNotNull() , assertTrue и т. Д. Вот подробное пояснение .


Информация для аннотации для теста JUnit:

@Test: аннотация Test указывает JUnit, что общедоступный метод void, к которому он присоединен, может быть запущен в качестве тестового примера. Чтобы запустить этот метод, JUnit сначала создает новый экземпляр класса, затем вызывает аннотированный метод.

@ Прежде: при написании тестов обычно обнаруживается, что для нескольких тестов нужны похожие объекты, созданные до их запуска. @Before метода public void с @Before заставляет этот метод запускаться до метода Test.

@After: Если вы выделяете внешние ресурсы в методе Before, вам необходимо освободить их после запуска теста. @After метода public void с @After приводит к тому, что этот метод запускается после метода Test. Все методы @After гарантированно выполняются, даже если метод Before или Test выдает исключение


Совет Быстрое создание тестовых классов в Android Studio

  • Поместите курсор на имя класса, для которого вы хотите создать тестовый класс.
  • Нажмите Alt + Enter (Windows).
  • Выберите «Создать тест», нажмите «Возврат».
  • Выберите методы, для которых вы хотите создать методы тестирования, нажмите «ОК».
  • Выберите каталог, в котором вы хотите создать тестовый класс.
  • Вы закончили, это то, что вы получаете, это ваш первый тест.

Совет Легко выполнять тесты в Android Studio

  • Щелкните правой кнопкой мыши тестовый пакет.
  • Выберите Run 'Tests in ...
  • Все тесты в пакете будут выполняться сразу.

Перемещение бизнес-логики из компонентов Android

Значительная часть результатов тестирования локальных JVM-модулей объясняется тем, как вы разрабатываете приложение. Вы должны проектировать его таким образом, чтобы вы могли отделить свою бизнес-логику от своих компонентов Android. Вот пример такого способа использования шаблона Model-View-Presenter . Давайте рассмотрим это, выполнив базовый экран регистрации, который требует только имя пользователя и пароль. Наше Android-приложение отвечает за проверку того, что имя пользователя, которое пользователь предоставляет, не пуст и что пароль имеет длину не менее восьми символов и содержит хотя бы одну цифру. Если имя пользователя / пароль действительны, мы выполняем наш вызов api для вызова, иначе мы выводим сообщение об ошибке.

Пример, в котором бизнес-логика сочетается с 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();
        }
    }
}

Пример, где бизнес-логика отделена от Android-компонента.

Здесь мы определяем в одном классе LoginContract, который будет содержать различные взаимодействия между нашими различными классами.

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

Наш LoginActivity по большей части тот же, за исключением того, что мы удалили ответственность за то, чтобы знать, как проверить форму регистрации пользователя (нашу бизнес-логику). LoginActivity теперь будет использовать наш новый LoginPresenter для проверки.

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);
    }
    ...
}

Теперь ваша бизнес-логика будет находиться в вашем новом классе 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();
        }
    }
}

И теперь мы можем создать локальные тесты JVM для вашего нового класса 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);
    }
}

Как вы можете видеть, когда мы извлекли нашу бизнес-логику из LoginActivity и поместили ее в POJO LoginPresenter. Теперь мы можем создавать локальные тесты JVM для нашей бизнес-логики.

Следует отметить, что из-за наших изменений в архитектуре существуют различные другие последствия, так как мы близки к соблюдению каждого класса с одной ответственностью, дополнительными классами и т. Д. Это просто побочные эффекты того, как я решил пойти на это развязка через стиль MVP. MVP - это всего лишь один из способов сделать это, но есть и другие альтернативы, которые вы можете посмотреть на MVVM . Вам просто нужно выбрать лучшую систему, которая работает для вас.

Начало работы с JUnit

Настроить

Чтобы начать модульное тестирование вашего проекта Android с помощью JUnit, вам нужно добавить зависимость JUnit к вашему проекту, и вам нужно создать тестовый источник, который будет содержать исходный код для модульных тестов. Проекты, созданные с помощью Android Studio, часто уже включают зависимость JUnit и исходный набор тестов

Добавьте следующую строку в файл build.gradle пределах зависимостей. Closure :

testCompile 'junit:junit:4.12'

Тест-классы JUnit расположены в специальном наборе-источнике с именем test . Если этот источник не существует, вам нужно создать новую папку самостоятельно. Структура папок стандартного проекта Android Studio (Gradle) выглядит следующим образом:

<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)

Если ваш проект не имеет папки /app/src/test вам необходимо создать его самостоятельно. В test папке вам также нужна папка java (создайте ее, если она не существует). Папка java в наборе test источников должна содержать ту же структуру пакета, что и ваш main источник.

Если правильная настройка вашей структуры проекта (в Android-представлении в Android Studio) должна выглядеть так:

настройка проекта

Примечание. Вы не обязательно должны иметь исходный набор androidTest , этот набор источников часто встречается в проектах, созданных Android Studio, и здесь приводится для справки.


Написание теста

  1. Создайте новый класс в test источнике.
    Щелкните правой кнопкой мыши тестовый источник, заданный в представлении проекта, выберите « New > « Java class .
    Наиболее используемым шаблоном имен является использование имени класса, которое вы собираетесь тестировать, с добавлением Test . Таким образом, StringUtilities становится StringUtilitiesTest .

  2. Добавьте аннотацию @RunWith
    Аннотации @RunWith необходимы, чтобы JUnit запускал тесты, которые мы собираемся определить в нашем тестовом классе. По умолчанию JUnit runner (для JUnit 4) является BlockJUnit4ClassRunner но вместо того, чтобы использовать этот запуск напрямую, более удобно использовать псевдоним JUnit4 который является сокращением для бегуна JUnit по умолчанию.

     @RunWith(JUnit4.class)
     public class StringUtilitiesTest {
     
     }
    
  3. Создать тест
    Единичный тест - это просто метод, который в большинстве случаев не должен прерываться при запуске. Другими словами, это не должно вызывать исключения. Внутри тестового метода вы почти всегда найдете утверждения, которые проверяют, выполнены ли особые условия. Если утверждение не выполняется, оно вызывает исключение, из-за которого метод / тест терпит неудачу. Метод проверки всегда аннотируется аннотацией @Test . Без этой аннотации JUnit не будет автоматически запускать тест.

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

    Примечание: в отличие от стандартных имен меток метода именования методов Java имена меток часто содержат символы подчеркивания.


Выполнение теста

  1. метод
    Чтобы запустить один метод тестирования, вы можете щелкнуть правой кнопкой мыши метод и нажать « Run 'addition_isCorrect()' или использовать сочетание клавиш ctrl+shift+f10 . Запустить единичный тест

    Если все настроено правильно, JUnit начинает запускать метод, и вы должны увидеть следующий интерфейс в Android Studio:

    Интерфейсный модуль Android Studio

  1. Учебный класс
    Вы также можете запустить все тесты, определенные в одном классе, щелкнув правой кнопкой мыши класс в представлении проекта и нажав « Run 'StringUtilitiesTest ' или воспользовавшись сочетанием клавиш ctrl+shift+f10 если вы выбрали класс в представлении проекта.

  2. Пакет (все)
    Если вы не будете запускать все тесты, определенные в проекте или в пакете, вы можете просто щелкнуть правой кнопкой мыши по пакету и нажать « Run ... же, как вы будете запускать все тесты, определенные в одном классе.

Исключения

JUnit также может использоваться для проверки того, выбрал ли метод конкретное исключение для данного ввода.

В этом примере мы проверим, действительно ли следующий метод генерирует исключение, если логический формат (ввод) не распознается / неизвестен:

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);
    }
}

Добавляя expected параметр к аннотации @Test , можно определить, какое исключение будет @Test . Тестирование модуля завершится неудачно, если это исключение не произойдет, и преуспеть, если действительно исключено исключение:

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

Это хорошо работает, однако, это ограничивает вас только одним тестовым случаем в рамках метода. Иногда вам может потребоваться проверить несколько случаев в рамках одного метода. Техника, которая часто используется для преодоления этого ограничения, заключается в использовании блоков try-catch и 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){
    }
}

Примечание. Некоторые считают, что это плохая практика для тестирования более чем одного случая внутри модульного теста.

Статический импорт

JUnit определяет довольно некоторые методы assertEquals по крайней мере один для каждого примитивного типа, и один для объектов доступен. Эти методы по умолчанию не имеют прямого доступа для вызова и должны быть вызваны следующим образом: Assert.assertEquals . Но поскольку эти методы используются так часто, люди почти всегда используют статический импорт, поэтому метод может быть непосредственно использован так, как если бы он был частью самого класса.

Чтобы добавить статический импорт для метода assertEquals используйте следующий оператор импорта:

import static org.junit.Assert.assertEquals;

Вы также можете статически импортировать все методы assert, включая assertArrayEquals , assertNotNull и assertFalse и т. Д., Используя следующий статический импорт:

import static org.junit.Assert.*;

Без статического импорта:

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

Со статическим импортом:

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


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow