Выполнение простых тестов JUnit в Android Studio (IntelliJ) при использовании конфигурации на основе Gradle

Я использую Android Studio/IntelliJ основываться на существующем Android проект и хотел бы добавить несколько простых JUnit модульные тесты. Какая папка подходит для добавления таких тестов?

Андроид Gradle Плагин определяет структуру каталогов с src/main/java для основного исходного кода и src/instrumentTest/java за Android тесты.

Попытка добавить мои тесты JUnit в instrumentTest не сработала для меня. Я могу запустить его как Android тест (это то, что этот каталог кажется), но это не то, что я ищу - я просто хочу запустить простой JUnit тестовое задание. Я попытался создать конфигурацию запуска JUnit для этого класса, но это также не сработало - я полагаю, потому что я использую каталог, помеченный как Android Тест вместо источника.

Если я создам новую исходную папку и помечу ее как таковую в структуре проекта, это будет уничтожено в следующий раз IntelliJ обновляет конфигурацию проекта из файлов сборки Gradle.

Что является более подходящим способом настройки тестов JUnit в основанном на Gradle проекте Android на IntelliJ? Какую структуру каталогов использовать для этого?

6 ответов

Решение

Начиная с Android Studio 1.1, ответ теперь прост: http://tools.android.com/tech-docs/unit-testing-support

Обычно вы не можете. Добро пожаловать в мир Android, где все тесты должны выполняться на устройстве (кроме Robolectric).

Основная причина в том, что на самом деле у вас нет исходных текстов фреймворка - даже если вы убедите IDE выполнить тест локально, вы сразу получите исключение "Stub! Не реализовано". "Зачем?" Вы можете спросить? Поскольку android.jar что SDK дает вам, на самом деле все заглушено - все классы и методы есть, но все они просто выдают исключение. Он здесь для того, чтобы предоставить API, но не для того, чтобы дать вам реальную реализацию.

Есть замечательный проект под названием http://robolectric.org/, который реализует множество фреймворков просто для того, чтобы вы могли запускать содержательные тесты. В сочетании с хорошей имитацией фреймворка (например, Mockito) он делает вашу работу управляемой.

Плагин Gradle: https://github.com/robolectric/robolectric-gradle-plugin

вступление

Обратите внимание, что на момент написания Robolectric 2.4 является последней версией и не поддерживает appcompat v7 библиотека. Поддержка будет добавлена ​​в выпуске robolectric 3.0 (пока нет ETA). Также ActionBar Sherlock может вызвать проблемы с робототехникой.

Чтобы использовать Robolectric в Android Studio, у вас есть 2 варианта:

(Вариант 1) - Запуск тестов JUnit в Android Studio с использованием модуля Java

Этот метод использует Java-модуль для всех ваших тестов с зависимостью от вашего Android-модуля и пользовательский тестовый прогон с некоторой магией:

Инструкции можно найти здесь: http://blog.blundellapps.com/how-to-run-robolectric-junit-tests-in-android-studio/

Также проверьте ссылку в конце этого поста для запуска тестов от Android Studio.

(Вариант 2) - Запуск тестов JUnit с Android Studio с использованием robolectric-gradle-plugin

Я столкнулся с несколькими проблемами при настройке тестов junit для запуска из gradle в Android Studio.

Это очень простой пример проекта для запуска тестов junit из основанного на gradle проекта в Android Studio: https://github.com/hanscappelle/android-studio-junit-robolectric Этот тест был протестирован с Android Studio 0.8.14, JUnit 4.10, плагин robolectric gradle 0.13+ и robolectric 2.3

Buildscript (проект /build.gradle)

Сценарий сборки - это файл build.gradle в корневом каталоге вашего проекта. Там я должен был добавить плагин robolectric gradle в classpath

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.13.2'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
        classpath 'org.robolectric:robolectric-gradle-plugin:0.13.+'

    }
}

allprojects {
    repositories {
        jcenter()
    }
}

Скрипт проекта проекта (App/build.gradle)

В сценарии сборки вашего модуля приложения используйте robolectric плагин, добавить robolectric Конфиг и добавить androidTestCompile зависимостей.

apply plugin: 'com.android.application'
apply plugin: 'robolectric'

android {
    // like any other project
}

robolectric {
    // configure the set of classes for JUnit tests
    include '**/*Test.class'
    exclude '**/espresso/**/*.class'

    // configure max heap size of the test JVM
    maxHeapSize = '2048m'

    // configure the test JVM arguments
    jvmArgs '-XX:MaxPermSize=512m', '-XX:-UseSplitVerifier'

    // configure whether failing tests should fail the build
    ignoreFailures true

    // use afterTest to listen to the test execution results
    afterTest { descriptor, result ->
        println "Executing test for {$descriptor.name} with result: ${result.resultType}"
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    androidTestCompile 'org.robolectric:robolectric:2.3'
    androidTestCompile 'junit:junit:4.10'
}

Создать тестовые классы JUnit

Теперь поместите тестовые классы в расположение по умолчанию (или обновите конфигурацию Gradle)

app/src/androidTest/java

И назовите ваши тестовые классы, заканчивающиеся на Test (или снова обновите config), расширяя junit.framework.TestCase и аннотировать методы испытаний с @Test,

package be.hcpl.android.mytestedapplication;

import junit.framework.TestCase;
import org.junit.Test;

public class MainActivityTest extends TestCase {

    @Test
    public void testThatSucceeds(){
        // all OK
        assert true;
    }

    @Test
    public void testThatFails(){
        // all NOK
        assert false;
    }
}

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

Затем выполните тесты, используя gradlew из командной строки (сделайте его исполняемым, используя chmod +x если нужно)

./gradlew clean test

Образец вывода:

Executing test for {testThatSucceeds} with result: SUCCESS
Executing test for {testThatFails} with result: FAILURE

android.hcpl.be.mytestedapplication.MainActivityTest > testThatFails FAILED
    java.lang.AssertionError at MainActivityTest.java:21

2 tests completed, 1 failed                                  
There were failing tests. See the report at: file:///Users/hcpl/Development/git/MyTestedApplication/app/build/test-report/debug/index.html
:app:test                      

BUILD SUCCESSFUL

Поиск проблемы

каталоги альтернативных источников

Точно так же, как вы можете иметь свои исходные файлы java где-то еще, вы можете перемещать свои тестовые исходные файлы. Просто обновите Gradle sourceSets конфигурации.

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        androidTest {
            setRoot('tests')
        }
    }

пакет org.junit не существует

Вы забыли добавить зависимость теста junit в скрипт сборки приложения

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    androidTestCompile 'org.robolectric:robolectric:2.3'
    androidTestCompile 'junit:junit:4.10'
}

java.lang.RuntimeException: заглушка!

Вы запускаете этот тест с конфигурациями запуска из Android Studio вместо командной строки (вкладка "Терминал" в Android Studio). Чтобы запустить его из Android Studio, вам необходимо обновить app.iml файл, в котором внизу должна быть запись jdk. Смотрите пример deckard-gradle для подробностей.

Полный пример ошибки:

!!! JUnit version 3.8 or later expected:

java.lang.RuntimeException: Stub!
    at junit.runner.BaseTestRunner.<init>(BaseTestRunner.java:5)
    at junit.textui.TestRunner.<init>(TestRunner.java:54)
    at junit.textui.TestRunner.<init>(TestRunner.java:48)
    at junit.textui.TestRunner.<init>(TestRunner.java:41)
    at com.intellij.rt.execution.junit.JUnitStarter.junitVersionChecks(JUnitStarter.java:190)
    at com.intellij.rt.execution.junit.JUnitStarter.canWorkWithJUnitVersion(JUnitStarter.java:173)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:56)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

ОШИБКА: для JAVA_HOME задан неверный каталог

Посмотрите этот ТАК вопрос для решения. Добавьте приведенный ниже экспорт в ваш профиль bash:

export JAVA_HOME=`/usr/libexec/java_home -v 1.7`  

Полный журнал ошибок:

ERROR: JAVA_HOME is set to an invalid directory: export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation.

Тестовый класс не найден

Если вы хотите запускать свои тесты из Android Studio Junit Test Runner, вместо этого вам придется немного расширить файл build.gradle, чтобы android studio могла найти ваши скомпилированные тестовые классы:

sourceSets {
    testLocal {
        java.srcDir file('src/test/java')
        resources.srcDir file('src/test/resources')
    }
}

android {

    // tell Android studio that the instrumentTest source set is located in the unit test source set
    sourceSets {
        instrumentTest.setRoot('src/test')
    }
}

dependencies {

    // Dependencies for the `testLocal` task, make sure to list all your global dependencies here as well
    testLocalCompile 'junit:junit:4.11'
    testLocalCompile 'com.google.android:android:4.1.1.4'
    testLocalCompile 'org.robolectric:robolectric:2.3'

    // Android Studio doesn't recognize the `testLocal` task, so we define the same dependencies as above for instrumentTest
    // which is Android Studio's test task
    androidTestCompile 'junit:junit:4.11'
    androidTestCompile 'com.google.android:android:4.1.1.4'
    androidTestCompile 'org.robolectric:robolectric:2.3'

}

task localTest(type: Test, dependsOn: assemble) {
    testClassesDir = sourceSets.testLocal.output.classesDir

    android.sourceSets.main.java.srcDirs.each { dir ->
        def buildDir = dir.getAbsolutePath().split('/')
        buildDir =  (buildDir[0..(buildDir.length - 4)] + ['build', 'classes', 'debug']).join('/')

        sourceSets.testLocal.compileClasspath += files(buildDir)
        sourceSets.testLocal.runtimeClasspath += files(buildDir)
    }

    classpath = sourceSets.testLocal.runtimeClasspath
}

check.dependsOn localTest

от: http://kostyay.name/android-studio-robolectric-gradle-getting-work/

Еще немного ресурсов

Лучшие статьи, которые я нашел вокруг этого:

Теперь это поддерживается в Android Studio, начиная с плагина Android Gradle 1.1.0, проверьте это:

https://developer.android.com/training/testing/unit-testing/local-unit-tests.html

Пример приложения с локальными модульными тестами на GitHub:

https://github.com/googlesamples/android-testing/tree/master/unittesting/BasicSample

Для Android Studio 1.2+ настроить проект для JUnit довольно просто, попробуйте следовать этому уроку:

Это самая простая часть настройки проекта для JUnit:

https://io2015codelabs.appspot.com/codelabs/android-studio-testing

Следуйте по прошедшей ссылке до тех пор, пока не пройдете " Проведение тестов "

Теперь, если вы хотите интегрироваться с тестом Intrumentation, следуйте инструкциям здесь:

https://io2015codelabs.appspot.com/codelabs/android-studio-testing

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

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

Другие вопросы по тегам