Ausführen einfacher JUnit-Tests unter Android Studio (IntelliJ) bei Verwendung einer Gradle-basierten Konfiguration


78

Ich verwende es Android Studio/IntelliJ, um auf einem vorhandenen AndroidProjekt aufzubauen, und möchte einige einfache JUnitKomponententests hinzufügen . Was ist der richtige Ordner, um solche Tests hinzuzufügen?

Das Android- GradlePlug-In definiert eine Verzeichnisstruktur mit src/main/javafür den Hauptquellcode und src/instrumentTest/javafür AndroidTests.

Der Versuch, meine JUnit-Tests in instrumentTest hinzuzufügen, hat bei mir nicht funktioniert. Ich kann es als AndroidTest ausführen (dafür scheint dieses Verzeichnis zu sein), aber das ist nicht das, wonach ich suche - ich möchte nur einen einfachen JUnitTest ausführen . Ich habe versucht, eine JUnit-Ausführungskonfiguration für diese Klasse zu erstellen, aber das hat auch nicht funktioniert. Ich nehme an, ich verwende ein Verzeichnis, das als AndroidTest anstelle von Quelle gekennzeichnet ist.

Wenn ich einen neuen Quellordner erstelle und ihn in der Projektstruktur als solchen markiere, wird dieser IntelliJgelöscht, wenn die Projektkonfiguration das nächste Mal aus den Gradle-Build-Dateien aktualisiert wird.

Was ist die geeignetere Methode zum Konfigurieren von JUnit-Tests in einem gradle-basierten Android-Projekt IntelliJ? Welche Verzeichnisstruktur soll dafür verwendet werden?


Leider kann ich Ihnen bei den Tests nicht helfen, da ich selbst immer noch damit zu kämpfen habe, aber Sie können dies verwenden, um zu verhindern, dass IntelliJ die java.srcDirs = ['src/main/java','src/instrumentTest/java']sourceSetsbuild.gradle
Rob Holmes

Das Einrichten macht keinen Spaß und ist auch nicht einfach zu warten, aber ich habe es irgendwie mit dem Standardordner /src/androidTest/javamit robolectric JUnit-Tests zum Laufen gebracht , siehe: stackoverflow.com/a/25473702/1406325
Flo

Android Studio unterstützt jetzt Local Unit Testing mit JUnit 4: stackoverflow.com/a/30273301/885464
Lorenzo Polidori

@ Julian Cerruti Update: Android Studio Demo zum Ausführen des Testfalls goo.gl/ac06C0 und Beispiel zum Ausführen des Netzwerkaufruftests goo.gl/bQFlmU
nitesh

Die Verzeichnisstrukturen für Tests und getestete Klassen müssen passen. Hier ist, wie es einfach geht: stackoverflow.com/a/36057080/715269
Gangnus

Antworten:



36

Normalerweise kannst du nicht. Willkommen in der Welt von Android, in der alle Tests auf einem Gerät (außer Robolectric) ausgeführt werden müssen.

Der Hauptgrund ist, dass Sie nicht über die Quellen des Frameworks verfügen. Selbst wenn Sie die IDE davon überzeugen, den Test lokal auszuführen, wird sofort die Ausnahme "Stub! Nicht implementiert" angezeigt. "Warum?" Sie könnten sich fragen? Weil das android.jar, was das SDK Ihnen bietet, tatsächlich alle ausgeblendet ist - alle Klassen und Methoden sind vorhanden, aber alle lösen nur eine Ausnahme aus. Es ist da, um eine API bereitzustellen, aber nicht, um Ihnen eine tatsächliche Implementierung zu geben.

Es gibt ein wundervolles Projekt namens Robolectric, das einen Großteil des Frameworks implementiert, damit Sie aussagekräftige Tests durchführen können. In Verbindung mit einem guten Mock-Framework (z. B. Mockito) ist Ihr Job überschaubar.

Gradle-Plugin: https://github.com/robolectric/robolectric-gradle-plugin


1
Danke, Deylan. Ich bin nach einfachen Tests, die keine Android-Infrastruktur verwenden, also ist es der richtige Weg, entweder ein neues Projekt zu erstellen, wie Sie es vorschlagen, oder die Gradle-Android-Konfiguration zu optimieren, um regelmäßige Tests zu ermöglichen. Leider konnte ich es immer noch nicht zum
Julian Cerruti

1
In diesem Fall möchten Sie ein neues einfaches Java-Gradle-Projekt (dh apply plugin: 'java') erstellen, es zu 'settings.gradle' hinzufügen, es als Abhängigkeit von Ihrem Android-Projekt ( compile project(':plainJavaProjectName')) verwenden und einfach die testAufgabe ausführen . (Nicht getestet, sollte aber auf jeden Fall funktionieren!)
Delyan

3
Tests in einem einfachen Java-Gradle-Projekt funktionieren problemlos mit der Befehlszeile, jedoch nicht in Android Studio, wo der Fehler "Klasse nicht gefunden MyTestClass" angezeigt wird. Das ist seltsam, weil AS und die Befehlszeile gradle auf die gleiche Weise verwenden sollten.
Lukas

1
Vermeiden Sie Gradle, wenn Sie JUnit-Tests verwenden möchten. Maven ist eine bessere Option.
Jeroen

3
Können Sie diese Aussage rechtfertigen? Warum ist Maven besser?
RichieHH

32

Intro

Beachten Sie, dass Robolectric 2.4 zum Zeitpunkt des Schreibens die neueste Version ist und keine Unterstützung für die appcompat v7Bibliothek bietet . Unterstützung wird in Robolectric 3.0 hinzugefügt (noch keine ETA ). Auch ActionBar Sherlockkönnen Probleme mit robolectric verursachen.

Um Robolectric in Android Studio zu verwenden, haben Sie zwei Möglichkeiten:

(Option 1) - Ausführen von JUnit-Tests mit Android Studio unter Verwendung eines Java-Moduls

Diese Technik verwendet ein Java-Modul für alle Ihre Tests mit einer Abhängigkeit von Ihrem Android-Modul und einen benutzerdefinierten Testläufer mit etwas Magie:

Anweisungen finden Sie hier: http://blog.blundellapps.com/how-to-run-robolectric-junit-tests-in-android-studio/

Überprüfen Sie auch den Link am Ende dieses Beitrags, um die Tests von Android Studio auszuführen.

(Option 2) - Ausführen von JUnit-Tests mit Android Studio unter Verwendung des Robolectric-Gradle-Plugins

Ich habe einige Probleme beim Einrichten von Junit-Tests für die Ausführung von Gradle in Android Studio festgestellt.

Dies ist ein sehr einfaches Beispielprojekt zum Ausführen von Junit-Tests aus einem gradle-basierten Projekt in Android Studio: https://github.com/hanscappelle/android-studio-junit-robolectric Dies wurde mit Android Studio 0.8.14, JUnit 4.10, getestet. robolectric gradle plugin 0.13+ und robolectric 2.3

Buildscript (project / build.gradle)

Das Build-Skript ist die Datei build.gradle im Stammverzeichnis Ihres Projekts. Dort musste ich dem Klassenpfad das robolectric gradle plugin hinzufügen

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

Projekt-Buildscript (App / build.gradle)

Verwenden Sie im Build-Skript Ihres App-Moduls das robolectricPlugin, fügen Sie robolectricconfig hinzu und fügen Sie androidTestCompileAbhängigkeiten hinzu.

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

Erstellen Sie JUnit-Testklassen

Setzen Sie nun die Testklassen an den Standardspeicherort (oder aktualisieren Sie die Gradle-Konfiguration).

app/src/androidTest/java

Benennen Sie Ihre Testklassen, die mit Test enden (oder aktualisieren Sie die Konfiguration erneut), junit.framework.TestCaseund erweitern und kommentieren Sie die Testmethoden mit @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;
    }
}

Tests ausführen

Führen Sie als Nächstes die Tests mit gradlew über die Befehlszeile aus (machen Sie sie chmod +xbei Bedarf mit ausführbar ).

./gradlew clean test

Beispielausgabe:

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

Fehlerbehebung

alternative Quellverzeichnisse

So wie Sie Ihre Java-Quelldateien an einem anderen Ort haben können, können Sie Ihre Testquelldateien verschieben. Aktualisieren Sie einfach die Gradle- sourceSetsKonfiguration.

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

        androidTest {
            setRoot('tests')
        }
    }

Paket org.junit existiert nicht

Sie haben vergessen, die Junit-Testabhängigkeit im App-Build-Skript hinzuzufügen

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

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

java.lang.RuntimeException: Stub!

Sie führen diesen Test mit den Ausführungskonfigurationen von Android Studio anstelle der Befehlszeile aus (Registerkarte Terminal in Android Studio). Um es von Android Studio aus auszuführen, müssen Sie die app.imlDatei aktualisieren , damit der JDK-Eintrag unten aufgeführt wird. Siehe Deckard-Gradle-Beispiel für Details.

Vollständiges Fehlerbeispiel:

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

FEHLER: JAVA_HOME wird auf ein ungültiges Verzeichnis gesetzt

In dieser SO-Frage finden Sie eine Lösung. Fügen Sie den folgenden Export zu Ihrem Bash-Profil hinzu:

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

Das vollständige Fehlerprotokoll:

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.

Testklasse nicht gefunden

Wenn Sie Ihre Tests stattdessen mit Android Studio Junit Test Runner ausführen möchten, müssen Sie die Datei build.gradle etwas erweitern, damit Android Studio Ihre kompilierten Testklassen finden kann:

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

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

Noch mehr Ressourcen

Die besten Artikel, die ich dazu gefunden habe, sind:



1

Für Android Studio 1.2+ ist das Einrichten eines Projekts für JUnit ziemlich einfach. Versuchen Sie, diesem Tutorial zu folgen:

Dies ist der einfachste Teil beim Einrichten eines Projekts für JUnit:

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

Folgen Sie dem letzten Link bis " Ausführen Ihrer Tests "

Wenn Sie nun in den Intrumentationstest integrieren möchten, folgen Sie von hier aus:

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


0

Weitere Informationen finden Sie in diesem Tutorial auf der offiziellen Website der Android-Entwickler. Dieser Artikel zeigt auch, wie Sie Modelle für Ihre Tests erstellen.

Übrigens sollten Sie beachten, dass der Umfang der Abhängigkeiten für den einfachen JUnit-Test "testCompile" sein sollte.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.