如何使用 Android Studio 运行单元测试

Posted

技术标签:

【中文标题】如何使用 Android Studio 运行单元测试【英文标题】:How to run unit tests with Android Studio 【发布时间】:2013-11-22 09:09:44 【问题描述】:

我正在为 gradle 使用 Jake 的 android 单元测试插件:https://github.com/JakeWharton/gradle-android-test-plugin

我的 build.gradle 看起来像这样:

dependencies 
// analytics
compile('com.crittercism:crittercism-android:3.0.11')

// retrofit
compile('com.squareup.retrofit:retrofit:1.2.2')
compile('com.squareup.okhttp:okhttp:1.2.1')

// dagger
compile('com.squareup.dagger:dagger:1.1.0')
compile('com.squareup.dagger:dagger-compiler:1.1.0')

// compatibility
compile('android.compatibility:android-support:v4-r13')
compile('com.actionbarsherlock:actionbarsherlock:4.4.0@aar')

// Picasso
compile('com.squareup.picasso:picasso:2.1.1')

// Otto
compile('com.squareup:otto:1.3.4')

// Tests
testCompile 'junit:junit:4.10'
testCompile 'org.robolectric:robolectric:2.2'
testCompile 'org.powermock:powermock-api-mockito:1.5.1'
testCompile 'org.easytesting:fest-assert-core:2.0M10'

很遗憾,我无法从 Android Studio 运行所有或特定的单元测试。我收到错误:

Exception in thread "main" java.lang.NoClassDefFoundError: junit/textui/ResultPrinter
 at java.lang.Class.forName0(Native Method)
 at java.lang.Class.forName(Class.java:171)
 at com.intellij.rt.execution.application.AppMain.main(AppMain.java:113)
Caused by: java.lang.ClassNotFoundException: junit.textui.ResultPrinter
 at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
 ... 3 more

这是正确的,因为运行命令行不包含我的 JUnit 依赖项:

/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java -ea -Didea.launcher.port=7533 "-Didea.launcher.bin.path=/Applications/Android Studio.app/bin" -Dfile.encoding=UTF-8 -classpath "/Applications/Android Studio.app/lib/idea_rt.jar:/Applications/Android Studio.app/plugins/junit/lib/junit-rt.jar:/Users/eugen/Development/SDK/android-sdk-macosx/platforms/android-18/android.jar:/Users/eugen/Development/SDK/android-sdk-macosx/platforms/android-18/data/res:/Users/eugen/Development/SDK/android-sdk-macosx/tools/support/annotations.jar:/Users/eugen/Development/Projects/eBuddy/xms/android/xms3-android/build/classes/alpha/debug:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.squareup.retrofit/retrofit/1.2.2/jar/cdf7b60568092fbcc7a254371c345e92f733c03c/retrofit-1.2.2.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.google.code.gson/gson/2.2.4/jar/a60a5e993c98c864010053cb901b7eab25306568/gson-2.2.4.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.squareup.okhttp/okhttp/1.2.1/jar/c3562574496bb4d452d6fc45b817577e98d08afe/okhttp-1.2.1.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.squareup/javawriter/2.1.1/jar/67ff45d9ae02e583d0f9b3432a5ebbe05c30c966/javawriter-2.1.1.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.squareup.dagger/dagger/1.1.0/jar/49f2061c938987c8e56679a731d74fd8448d8742/dagger-1.1.0.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.squareup.picasso/picasso/2.1.1/jar/ab19bfb23f641f189b6dca9a4d393f8dc291103a/picasso-2.1.1.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.squareup/otto/1.3.4/jar/4d72fb811c7b3c0e7f412112020d4430f044e510/otto-1.3.4.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.squareup.dagger/dagger-compiler/1.1.0/jar/ddb38c2be31deeb7a001177f7c358665e350d646/dagger-compiler-1.1.0.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/javax.inject/javax.inject/1/jar/6975da39a7040257bd51d21a231b76c915872d38/javax.inject-1.jar:/Users/eugen/Development/Projects/eBuddy/xms/android/xms3-android/build/exploded-bundles/ComActionbarsherlockActionbarsherlock440.aar/res:/Users/eugen/Development/Projects/eBuddy/xms/android/xms3-android/build/exploded-bundles/ComActionbarsherlockActionbarsherlock440.aar/classes.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.squareup.okhttp/okhttp-protocols/1.2.1/jar/ec2beaefef3bd4f680c17fad8e72e66f2a006f1/okhttp-protocols-1.2.1.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/com.crittercism/crittercism-android/3.0.11/jar/e30c21ae491d780622ecaee2752969be98140c3/crittercism-android-3.0.11.jar:/Users/eugen/.gradle/caches/artifacts-26/filestore/android.compatibility/android-support/v4-r13/jar/bd6479f5dd592790607e0504e66e0f31c2b4d308/android-support-v4-r13.jar" com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 @/private/var/folders/wq/knhztnf105v2_p1t580tj8h80000gp/T/idea_junit701450667388095664.tmp @w@/private/var/folders/wq/knhztnf105v2_p1t580tj8h80000gp/T/idea_working_dirs_junit4927192380605663413.tmp -socket63849

我想知道是否有人能够在 Android Studio 中运行单元测试?如果可以的话怎么做?

【问题讨论】:

如果你还在寻找,试试这个帖子element84.com/easy-testing-with-android-studio.html 感谢您的分享,但我正在寻找如何在工作室中运行测试的方法。特别是我需要能够在 TDD 会话期间运行一项特定测试。 如果你使用 Jake Wharton 的 android test plugin for gradle 你在 build.gradle 中指定的更少,并且使用gradle check运行所有测试 您不能将 junit 3 与 robolectric 一起使用 这在 Android Studio 中真是太令人生气了 :( 【参考方案1】:

只需在 /src 下添加名为 instrumentTest 的文件夹 它应该像这样在里面有/java

然后扩展类ActivityTestCase(或任何其他android unit-test-class),例如

package com.example.app.test;

import android.test.ActivityTestCase;

import junit.framework.Assert;


public class MainActivityTest extends ActivityTestCase 


public void testHappy()
    Assert.assertTrue(true);


 

右键单击绿色的 java 目录并选择运行所有测试 你应该得到这个:

祝你好运

【讨论】:

我把我的答案移到了这里(我想把答案放在首位),这是在 android studio 中运行单元测试所必须做的。至少这是我理解你想要做的,我理解你的问题错了吗? 我要求 Robolectric 单元测试不是工具 抱歉,我没有注意到 - 我教的是不同的问题,你要我删除答案吗? 你可以保留它。所以也许有些人会觉得它很有用 看来在Android Studio 0.5.7上,“instrumentTest”应该重命名为“androidTest”【参考方案2】:

AS 1.1+ 更新,android gradle 插件 1.1+

终于不用花招就可以了。这是一个项目示例,展示了如何在Android Studio v1.1+android gradle plugin v1.1+ 中设置Robolectric 测试: https://github.com/nenick/AndroidStudioAndRobolectric

您还可以找到可能的问题和解决方法。是的,Robolectric 很复杂,并且没有得到 Google 的官方支持,所以它仍然存在一些问题。但在大多数情况下,它都能发挥作用,并为您的项目带来巨大的价值。

我也鼓励您开始使用Robolectric v3+。它几乎已经发布并且足够稳定。

AS 0.x 和 1.0x 以及 1.1 以下的 android gradle 插件版本的旧答案

我在朋友的帮助下成功了。

所以基本上你需要进行下一个更改才能在 Android Studio 中运行 Robolectric 单元测试:

    复制你的类路径进行测试(你可以在“运行”日志的第一行找到它) 为您的单元测试打开运行配置 将工作目录更改为存在 AndroidManifest.xml 的文件夹 添加虚拟机选项-classpath "<path_to_project_folder>/build/test-classes:<path_to_gradle_cache>/caches/modules-2/files-2.1/junit/junit/4.11/4e031bb61df09069aeb2bffb4019e7a5034a4ee0/junit-4.11.jar:<your old classpath>"

对我来说,新类路径的开始是这样的:

/Users/emartynov/Development/Projects/work/android.project/build/test-classes:/Users/emartynov/.gradle/caches/modules-2/files-2.1/junit/junit/4.11/4e031bb61df09069aeb2bffb4019e7a5034a4ee0/junit-4.11.jar

问题:

    您只能为调试变体运行测试 每个新的测试运行配置都需要进行此类手动更改。但这只是复制/粘贴两个编辑字段

我有 Android Studio 0.6 版本。这又是我的build.gradle 文件的一部分:

buildscript 
  repositories 
    mavenCentral()
    maven  url 'https://github.com/rockerhieu/mvn-repo/raw/master/' 
  

  dependencies 
    classpath 'com.android.tools.build:gradle:0.11.+'
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.3'
  //  classpath 'org.robolectric.gradle:gradle-android-test-plugin:0.10.1'
    classpath 'org.robolectric.gradle:gradle-android-test-plugin:0.10.1-SNAPSHOT'
    classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.10.+'
  


apply plugin: 'android-sdk-manager'
apply plugin: 'android'
apply plugin: 'android-apt'
apply plugin: 'android-test'

repositories 
  mavenCentral()


android 
  compileSdkVersion 19
  buildToolsVersion "19.1.0"

  packagingOptions 
    exclude 'META-INF/NOTICE'
    exclude 'META-INF/NOTICE.txt'
    exclude 'META-INF/notice.txt'
    exclude 'META-INF/LICENSE'
    exclude 'META-INF/LICENSE.txt'
    exclude 'META-INF/license.txt'
    exclude 'META-INF/ASL2.0'
    exclude 'LICENSE.txt'
  

  defaultConfig 
    minSdkVersion 14
    targetSdkVersion 19
    versionCode 1
    versionName "0.9.0"
  

  compileOptions 
    sourceCompatibility JavaVersion.VERSION_1_7
    targetCompatibility JavaVersion.VERSION_1_7
  

  sourceSets 
    androidTest.setRoot( 'src/test' )
  


dependencies 
  // butter knife
  compile 'com.jakewharton:butterknife:5.0.0'
  // dagger
  compile 'com.squareup.dagger:dagger:1.2.1'

  // apt
  apt 'com.squareup.dagger:dagger-compiler:1.+'

  // AS tests
  androidTestCompile 'junit:junit:4.+'
  androidTestCompile( 'org.robolectric:robolectric:2.3' ) 
    exclude group: 'commons-logging'
    exclude group: 'org.apache.httpcomponents'
  
  androidTestCompile 'com.squareup:fest-android:1.+'
  androidTestCompile 'org.mockito:mockito-all:1.9.+'
  androidTestCompile 'org.easytesting:fest-assert-core:2.0M10'
  androidTestCompile( 'org.skyscreamer:jsonassert:1.2.+' ) 
    exclude group: 'org.json'
  

  // tests
  testCompile 'junit:junit:4.+'
  testCompile( 'org.robolectric:robolectric:2.3' ) 
    exclude group: 'commons-logging'
    exclude group: 'org.apache.httpcomponents'
  
  testCompile 'com.squareup:fest-android:1.+'
  testCompile 'org.mockito:mockito-all:1.9.+'
  testCompile 'org.easytesting:fest-assert-core:2.0M10'
  testCompile 'com.squareup.dagger:dagger-compiler:1.+'
  testCompile( 'org.skyscreamer:jsonassert:1.2.+' ) 
    exclude group: 'org.json'
  

【讨论】:

【参考方案3】:

我遇到了这个问题并找到了解决方案 - 将分解包 (.aar) 中的 classes.jar 包含在构建文件夹中。不过,我认为这对在 .aar 依赖项中查找资源没有帮助。

testCompile fileTree(dir: "$project.buildDir/exploded-bundles", include: "**/classes.jar")

编辑:自 Android Gradle 构建工具 0.9.0 以来,依赖项已更改为:

androidTestCompile fileTree(dir: "$project.buildDir/exploded-aar", include: "**/classes.jar")

编辑 2: 由于 Android Gradle 构建工具 0.10.0 依赖项已更改为:

androidTestCompile fileTree(dir: "$project.buildDir/../../build/exploded-aar", include: "**/classes.jar")

注意:相对路径可能因您的项目结构而异。

【讨论】:

抱歉,这对运行 Robolectric 单元测试没有帮助 试过了,还是开始Exception in thread "main" java.lang.NoClassDefFoundError: junit/textui/ResultPrinter -- 好像是在运行我的系统 JDK /Library/Java/JavaVirtualMachines/jdk1.7.0_55.jdk/Contents/Home/bin/java 可以吗? @AlexChaffee with gradle build tools 0.10.0 爆炸的 aars 的位置再次改变(见更新的答案) - 这可能是你的问题。 关于“NoClassDefFoundError:我按照此处的说明操作 (***.com/questions/24826252/…)。将 <output-test ... 指令添加到我的 .iml 文件有助于解决此问题。【参考方案4】:

我在使用 AS 1.2.2 时遇到了类似的问题。

我按照here 的步骤操作。基本上:

打开“构建变体”工具窗口(参见链接上的图片)并将“测试工件”下拉菜单更改为“单元测试”。 为您的测试源代码创建一个目录,即src/test/java,并将您的测试移动到那里的相应包中。

确保您的build.gradle 文件的以下部分包含这些:

dependencies  
    testCompile 'junit:junit:4.12'


android 
    sourceSets 
        test 
            resources 
                srcDir "test"
            
        
    

瞧!右键单击您的测试用例并选择 JUnit 风格。

顺便说一句,当您更改“构建变体”工具时,它似乎会切换 JUnit/Android 测试的可见性,所以我猜您可以测试为 JUnit 或 Android,但不能同时测试两者。

【讨论】:

感谢您的回答!这个问题不再相关了:)顺便说一句,Android Studio 1.3 稳定版已经发布,1.4 版现在正在预览中(如果你不害怕的话)【参考方案5】:

对于后代Android Studio 2.0+ 支持在没有插件的情况下运行单元测试。

可以通过菜单 Run > Edit Configurations...访问此屏幕

【讨论】:

以上是关于如何使用 Android Studio 运行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

在 Android Studio 中运行所有单元测试

如何编写脚本自动运行android studio测试用例

Android Studio 单元测试配置

Android studio 怎么使用单元测试(不需要device)

在 Android Studio 中运行参数化单元测试时,未找到给定的测试包括错误

Android Studio系列-Activity单元测试