使用基于 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 运行配置,但这也没有用——我猜是因为我使用的目录标记为 Android
Test 而不是 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文件