简体   繁体   English

使用基于Gradle的配置时,在Android Studio(IntelliJ)上运行简单的JUnit测试

[英]Running simple JUnit tests on Android Studio (IntelliJ) when using a Gradle-based configuration

I am using Android Studio/IntelliJ to build on an existing Android project and would like to add some simple JUnit unit tests. 我正在使用Android Studio/IntelliJ构建现有的Android项目,并希望添加一些简单的JUnit单元测试。 What is the right folder to add such tests on? 添加此类测试的正确文件夹是什么?

The android Gradle plug-in defines a directory structure with src/main/java for the main source code and src/instrumentTest/java for Android tests. android Gradle插件为主要源代码定义了src/main/java的目录结构,为Android测试定义了src/instrumentTest/java

Trying to add my JUnit tests in instrumentTest didn't work for me. 试图在instrumentTest中添加我的JUnit测试对我来说不起作用。 I can run it as an Android test (that's what that directory seems for) but that's not what I'm looking for - I just want to run a simple JUnit test. 我可以将它作为Android测试运行(这就是该目录所针对的)但这不是我想要的 - 我只想运行一个简单的JUnit测试。 I tried creating a JUnit run configuration for this Class but that also didn't work - I'm supposing because I'm using a directory that is flagged as Android Test instead of Source. 我尝试为这个类创建一个JUnit运行配置但是也没有用 - 我想是因为我使用的是一个标记为Android Test而不是Source的目录。

If I create a new source folder and marki it as such in Project Structure, this will get wiped next time IntelliJ refreshes the project configuration from the gradle build files. 如果我在项目结构中创建一个新的源文件夹并将其标记为这样,则下次IntelliJ从gradle构建文件刷新项目配置时,这将被删除。

What is the more appropriate way of configuring JUnit tests in an gradle-based android project on IntelliJ ? IntelliJ上基于gradle的android项目中配置JUnit测试的更合适的方法是什么? Which directory structure to use for this? 使用哪个目录结构?

Normally, you can't. 通常情况下,你不能。 Welcome to the world of Android, where all tests must run on a device(except Robolectric). 欢迎来到Android世界,所有测试都必须在设备上运行(Robolectric除外)。

The main reason is that you don't actually have the framework's sources - even if you convince the IDE to run the test locally, you will immediately get a "Stub! Not implemented" exception. 主要原因是您实际上没有框架的源 - 即使您说服IDE在本地运行测试,您也会立即获得“Stub!Not implemented”异常。 "Why?" “为什么?” you might wonder? 你可能想知道? Because the android.jar that the SDK gives you is actually all stubbed out - all the classes and methods are there but they all just throw an exception. 因为SDK给你的android.jar实际上都是存根 - 所有的类和方法都存在,但它们都只是抛出异常。 It's there to provide an API but not there to give you any actual implementation. 它提供了一个API,但没有给你任何实际的实现。

There's a wonderful project called Robolectric which implements a lot of the framework just so you can run meaningful tests. 有一个很棒的项目叫Robolectric ,它实现了很多框架,所以你可以运行有意义的测试。 Coupled with a good mock framework (eg, Mockito), it makes your job manageable. 再加上一个好的模拟框架(例如,Mockito),它可以让你的工作变得易于管理。

Gradle plugin: https://github.com/robolectric/robolectric-gradle-plugin Gradle插件: https//github.com/robolectric/robolectric-gradle-plugin

Intro 介绍

Note that at the time of writing robolectric 2.4 is the latest version and has no support for appcompat v7 library. 请注意,在撰写本文时,robolectric 2.4是最新版本,不支持appcompat v7库。 Support wil be added in robolectric 3.0 release ( no ETA yet ). 支持将添加到robolectric 3.0版本中( 尚无ETA )。 Also ActionBar Sherlock can cause issues with robolectric. ActionBar Sherlock也可能导致robolectric出现问题。

To use Robolectric within Android Studio you have 2 options: 要在Android Studio中使用Robolectric,您有两种选择:

(Option 1) - Running JUnit tests with Android Studio using a Java module (选项1) - 使用Java模块在Android Studio上运行JUnit测试

This technique uses a java module for all your tests with a dependency to your android module and a custom test runner with some magic: 这个技术使用java模块进行所有测试,依赖于你的android模块和一个带有魔法的自定义测试运行器:

Instructions can be found here: http://blog.blundellapps.com/how-to-run-robolectric-junit-tests-in-android-studio/ 说明可以在这里找到: http//blog.blundellapps.com/how-to-run-robolectric-junit-tests-in-android-studio/

Also check the link at the end of that post for running the tests from android studio. 还要检查该帖子末尾的链接,以便从android studio运行测试。

(Option 2) - Running JUnit Tests with Android Studio using robolectric-gradle-plugin (选项2) - 使用robolectric-gradle-plugin在Android Studio上运行JUnit测试

I encountered a few issues setting up junit tests to run from gradle in Android Studio. 我在Android Studio中设置了从gradle运行的junit测试时遇到了一些问题。

This is a very basic sample project for running junit tests from a gradle based project in Android Studio: https://github.com/hanscappelle/android-studio-junit-robolectric This was tested with Android Studio 0.8.14, JUnit 4.10, robolectric gradle plugin 0.13+ and robolectric 2.3 这是一个非常基本的示例项目,用于在Android Studio中从基于gradle的项目运行junit测试: https//github.com/hanscappelle/android-studio-junit-robolectric这是使用Android Studio 0.8.14,JUnit 4.10测试的, robolectric gradle插件0.13+和robolectric 2.3

Buildscript (project/build.gradle) Buildscript(project / build.gradle)

The build script is the build.gradle file in the root of you project. 构建脚本是项目根目录中的build.gradle文件。 There I had to add robolectric gradle plugin to classpath 我必须在类路径中添加robolectric gradle插件

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

Project buildscript (App/build.gradle) 项目buildscript(App / build.gradle)

In the build script of your app module use the robolectric plugin, add robolectric config and add androidTestCompile dependencies. 在你的app模块的构建脚本中使用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'
}

Create JUnit Test Classes 创建JUnit测试类

Now put the test classes in the default location (or update gradle config) 现在将测试类放在默认位置(或更新gradle配置)

app/src/androidTest/java

And name your tests classes ending with Test (or again update config), extending junit.framework.TestCase and annotate test methods with @Test . 并命名以Test结尾的测试类(或再次更新配置),扩展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;
    }
}

Execute Tests 执行测试

Next execute the tests using gradlew from command line (make it executable using chmod +x if needed) 接下来使用命令行中的gradlew执行测试(如果需要,使用chmod +x使其可执行)

./gradlew clean test

Sample output: 样本输出:

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

Troubleshooting 故障排除

alternative source directories 替代源目录

Just like you can have your java source files somewhere else you can move your test source files. 就像您可以在其他地方拥有Java源文件一样,您可以移动测试源文件。 Just update gradle sourceSets config. 只需更新gradle sourceSets配置即可。

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

        androidTest {
            setRoot('tests')
        }
    }

package org.junit does not exist 包org.junit不存在

You forgot to add the junit test dependency in the app build script 您忘记在应用构建脚本中添加junit测试依赖项

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

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

java.lang.RuntimeException: Stub! java.lang.RuntimeException:Stub!

You're running this test with the run configurations from Android Studio instead of command line (Terminal tab in Android Studio). 您使用Android Studio中的运行配置而不是命令行(Android Studio中的终端选项卡)运行此测试。 To run it from Android Studio you'll have to update the app.iml file to have the jdk entry listed at the bottom. 要从Android Studio运行它,您必须更新app.iml文件以在底部列出jdk条目。 See deckard-gradle example for details. 有关详细信息,请参阅deckard-gradle示例

Complete error example: 完整的错误示例:

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

ERROR: JAVA_HOME is set to an invalid directory 错误:JAVA_HOME设置为无效目录

See this SO question for a solution. 请参阅此SO问题以获得解决方案。 Add the below export to you bash profile: 将以下导出添加到您的bash配置文件中:

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

The complete error log: 完整的错误日志:

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.

Test Class not found 未找到测试类

If you want to run your tests from Android Studio Junit Test runner instead you'll have to expand the build.gradle file a little more so that android studio can find your compiled test classes: 如果你想从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

from: http://kostyay.name/android-studio-robolectric-gradle-getting-work/ 来自: http//kostyay.name/android-studio-robolectric-gradle-getting-work/

Some more resources 一些更多的资源

The best articles I found around this are: 我发现的最好的文章是:

从Android Studio 1.1开始,答案很简单: http//tools.android.com/tech-docs/unit-testing-support

This is now supported in Android Studio starting with Android Gradle plugin 1.1.0, check this out: 从Android Gradle插件1.1.0开始,Android Studio现在支持此功能,请查看以下内容:

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

Sample app with local unit tests on GitHub: 在GitHub上使用本地单元测试的示例应用程序:

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

For Android Studio 1.2+ setting up a project for JUnit is pretty simple try to follow along this tutorial: 对于Android Studio 1.2+ ,为JUnit设置项目非常简单,请尝试按照本教程进行操作:

This is the simplest part setting up a project for JUnit: 这是为JUnit设置项目的最简单部分:

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

Follow along the past link until " Running your tests " 按照过去的链接,直到“ 运行您的测试

Now if you want to integrate with intrumentation test follow along from here: 现在,如果您想要与intrumentation测试集成,请从这里开始:

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

Please see this tutorial from the Android Developers official site. 请从Android开发者官方网站上查看本教程 This article also shows how to create mock-ups for your testing. 本文还介绍了如何为测试创建模型。

By the way, you should note that the scope of the dependencies for simple JUnit test should be "testCompile". 顺便说一句,您应该注意,简单JUnit测试的依赖关系的范围应该是“testCompile”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM