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

Posted

技术标签:

【中文标题】使用基于 Gradle 的配置时在 Android Studio (IntelliJ) 上运行简单的 JUnit 测试【英文标题】:Running simple JUnit tests on Android Studio (IntelliJ) when using a Gradle-based configuration 【发布时间】:2013-07-24 13:48:09 【问题描述】:

我正在使用android Studio/IntelliJ 构建现有的Android 项目,并想添加一些简单的JUnit 单元测试。添加此类测试的正确文件夹是什么?

android Gradle 插件定义了一个目录结构,src/main/java 用于主要源代码,src/instrumentTest/java 用于Android 测试。

尝试在 instrumentTest 中添加我的 JUnit 测试对我不起作用。我可以将它作为Android 测试运行(这就是那个目录的用途),但这不是我想要的——我只想运行一个简单的JUnit 测试。 我尝试为这个类创建一个 JUnit 运行配置,但这也没有用——我猜是因为我使用的目录标记为 AndroidTest 而不是 Source。

如果我创建一个新的源文件夹并在项目结构中将其标记为这样,那么下次 IntelliJ 从 gradle 构建文件刷新项目配置时,它将被擦除。

IntelliJ 上基于 gradle 的 android 项目中配置 JUnit 测试的更合适的方法是什么?使用哪种目录结构?

【问题讨论】:

不幸的是,我无法帮助您进行测试,因为我自己仍在为此苦苦挣扎,但是您可以使用它来阻止 IntelliJ 擦除源文件夹:sourceSets 部分中的java.srcDirs = ['src/main/java','src/instrumentTest/java'] build.gradle 设置起来并不有趣,维护起来也不简单,但我不知何故使用默认的 /src/androidTest/java 文件夹和 robolectric JUnit 测试让它运行,请参阅:***.com/a/25473702/1406325 Android Studio 现在支持使用 JUnit 4 进行本地单元测试:***.com/a/30273301/885464 @Julian Cerruti 更新:Android Studio 演示如何运行测试用例goo.gl/ac06C0 和运行网络调用测试的示例goo.gl/bQFlmU 测试和测试类的目录结构必须适合。以下是如何轻松做到这一点:***.com/a/36057080/715269 【参考方案1】:

简介

请注意,在撰写本文时,robolectric 2.4 是最新版本,不支持 appcompat v7 库。将在 robolectric 3.0 版本中添加支持(尚无 ETA)。 ActionBar Sherlock 也可能导致 robolectric 出现问题。

要在 Android Studio 中使用 Robolectric,您有 2 个选项:

(选项 1)- 使用 Java 模块在 Android Studio 中运行 JUnit 测试

这项技术使用一个 java 模块来进行所有测试,并依赖于你的 android 模块和一个具有一些魔力的自定义测试运行器:

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

还可以查看该帖子末尾的链接以从 android studio 运行测试。

(选项 2)- 使用 robolectric-gradle-plugin 在 Android Studio 中运行 JUnit 测试

我在设置 junit 测试以在 Android Studio 中从 gradle 运行时遇到了一些问题。

这是一个非常基本的示例项目,用于从 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 测试的

构建脚本(项目/build.gradle)

构建脚本是项目根目录中的 build.gradle 文件。在那里我不得不将robolectric gradle plugin 添加到类路径

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 结尾(或再次更新配置)命名您的测试类,扩展 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 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)

错误:JAVA_HOME 设置为无效目录

请参阅this SO question 以获取解决方案。将以下导出添加到您的 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/

更多资源

我发现的最好的文章是:

http://tryge.com/2013/02/28/android-gradle-build/ http://kostyay.name/android-studio-robolectric-gradle-getting-work/ http://www.element84.com/easy-testing-with-android-studio.html http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Sourcesets-and-Dependencies

【讨论】:

【参考方案2】:

请参阅 Android 开发者官方网站上的 tutorial。本文还介绍了如何为您的测试创建模型。

顺便提一下,简单JUnit测试的依赖范围应该是“testCompile”。

【讨论】:

【参考方案3】:

对于 Android Studio 1.2+,为 JUnit 设置项目非常简单尝试按照本教程进行操作:

这是为 JUnit 设置项目的最简单部分:

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

沿着过去的链接一直到“Running your tests”

现在,如果您想与仪器测试集成,请从这里开始:

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

【讨论】:

【参考方案4】:

从 Android Gradle 插件 1.1.0 开始,Android Studio 现在支持此功能,请查看:

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

GitHub 上带有本地单元测试的示例应用:

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

【讨论】:

github链接不可用【参考方案5】:

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

【讨论】:

这是否意味着 Robolectric 不再有用?这基本上会做同样的事情吗? 注意:从 Android Studio 2.0 Beta5 开始,链接中描述的“Test Artifact”选择器缺失,默认情况下同时启用两种模式(junit 和仪器)。请参阅此处了解更多信息***.com/questions/35708263/…【参考方案6】:

通常情况下,你不能。欢迎来到 Android 世界,所有测试都必须在设备上运行(Robolectric 除外)。

主要原因是您实际上没有框架的源代码 - 即使您说服 IDE 在本地运行测试,您也会立即收到“存根!未实现”异常。 “为什么?”你可能想知道?因为 SDK 提供给您的 android.jar 实际上都被删除了——所有的类和方法都在那里,但它们都只是抛出一个异常。它提供 API,但不提供任何实际实现。

有一个很棒的项目叫做Robolectric,它实现了很多框架,这样你就可以运行有意义的测试。再加上一个好的模拟框架(例如,Mockito),它使您的工作易于管理。

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

【讨论】:

谢谢你,德兰。我追求的是不使用任何 Android 基础设施的简单测试,因此要么像您建议的那样创建一个新项目,要么调整 Gradle Android 配置以适应常规测试。不幸的是,我仍然无法让它工作 - 由于某种原因它一直失败 - 但如果我让它工作,我会发布结果 在这种情况下,您想创建一个新的普通 java Gradle 项目(即apply plugin: 'java'),将其添加到“settings.gradle”,将其作为 Android 项目的依赖项(@987654325 @),然后运行 ​​test 任务。 (未经测试,但绝对可以工作!) 普通 java gradle 项目中的测试在命令行下可以正常工作,但在 Android Studio 中却没有,我收到“class not found MyTestClass”错误。这很奇怪,因为 AS 和命令行应该以相同的方式使用 gradle。 如果要使用 JUnit 测试,请避免使用 gradle,maven 是更好的选择。 你能证明这种说法是正确的吗?为什么 Maven 更好?

以上是关于使用基于 Gradle 的配置时在 Android Studio (IntelliJ) 上运行简单的 JUnit 测试的主要内容,如果未能解决你的问题,请参考以下文章

Android Studio的settings.gradle文件

Android Gradle插件开发

理解与配置android studio中的gradle

Gradle&Maven-Android Gradle 常用命令参数及解释

Android Studio之gradle的配置与介绍

Android Studio下项目构建的Gradle配置及打包应用变体