注意:本文须要使用Android Studio1.4 以上的版本。html
Android设备内存,CPU和电池都有限。应用的行为也外部因素有关,如链接性、系统利用等。所以调试、测试和优化Android应用很是重要。java
Android的测试不可能覆盖全部Android设备,一般只覆盖典型设备。确保应用至少覆盖尽量低的配置设备上使用和尽量高的配置设备,例如像素密度、屏幕分辨率等。python
2015年Android应用程的工具和框架的支持有巨大的改善。Android测试系统已经更新到基于JUnit4中,你能够在Java虚拟机或在Android运行时运行单元测试。此外谷歌推出了一款名为Espresso的用户界面测试框架。android
Android应用的测试内容通常来讲应该专一于测试应用的业务逻辑。建议:web
70-80%的单元测试以确保您的代码的稳定性shell
20-30%的功能测试确保应用能运做服务器
有交互的状况下还须要考虑跨应用测试app
Android的单元测试是基于JUnit的。可分为:框架
本地单元测试 - 能够在JVM上运行测试(速度快,优先考虑)。异步
Instrumented单元测试 - 须要Android系统
Android的Gradle插件支持在JVM上执行Android单元测试。它使用特殊版本的android.jar(也称为 Android mockable jar)支持单元测试,使全部字段,方法和类可用。任何调用到Android mockable JAR默认都是异常。快速可是不能测试安卓相关内容。Instrumented可测试Android API。
建议:
app/src/main/java - 源代码
app/src/test/java - 本地测试
app/src/androidTest/java - Instrumented单元测试
若是你这些约定,Android构建系统会自动在JVM上运行单元测试、在Android设备上运行安卓测试。
指定测试类型:
查看测试执行:
若是看到"error duplicate files in path. Path in archive: LICENSE.txt"错误,修改app/gradle.build
android { packagingOptions { exclude 'LICENSE.txt' } }
Android使用unit test这个术语描述本地JVM而非Android Runtime上运行的测试。
unit test测试组件功能。例如假设Android activity的一个按钮用于启动另外一个activity。单元测试肯定是否发出相应的intent,但部保证另外一个activity已启动。
unit test依靠修改后的android.jar
执行,这个jar文件中全部的final
修饰符都被去掉。修改后容许使用mock库,如Mockito。默认这个android.jar
中的全部方法抛出异常。这种缺省行为保证单元测试只会测试本身代码,不会依赖Android平台的任何特定行为。若是想使用Android平台的特定行为,可使用mock框架替换相应调用。
单元测试约定的位置:app/src/test/
目录,并须要添加相应配置到Gradle构建文件中:
dependencies { // Unit testing dependencies testCompile 'junit:junit:4.12' // Set this dependency if you want to use the Hamcrest matcher library testCompile 'org.hamcrest:hamcrest-library:1.3' // more stuff, e.g., Mockito }
使用gradlew test
命令可运行单元测试。
在Android Studio的Build Variants窗口的Test Artifact中选择Unit Tests,单元测试将在JVM上运行。
Android Studio有两种类型,能够在构建变量视图中选择。若是在该视图中选择单元测试,单元测试在JVM上执行。
从运行Android的工做室Android的测试
运行单元测试,先选择的单元测试,在项目窗口中的测试类单击右键并选择运行。
测试报告在app/build/reports/tests/debug/
目录。index.html
是测试概述,它连接到单个测试页。
也能够配置Gradle构建系统,让android.jar
中的方法均返回缺省值而不是抛出异常:
android { // ... testOptions { unitTests.returnDefaultValues = true } }
在app/src/test/
目录中为ConverterUtil
类建立以下两个测试方法。
在模块的app/build.gradle中添加依赖:testCompile 'junit:junit:4.12'
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.1.1' }
在菜单栏选择"Run"->"Edit configuration", 增长Junit测试(第一次可能没有)。
而后为ConverterUtil添加unit test, 在左侧窗口双击
ConverterUtil打开ConverterUtil.java, 在左侧窗口选中类定义中的ConverterUtil,右键弹出菜单中选择"Go To" -> "Test",选择"Create New Test":
生成的文件ConverterUtilTest.java以下:
package com.vogella.android.temperatureconverter; import junit.framework.TestCase; import org.junit.Test; import static org.junit.Assert.*; /** * Created by andrew on 15-11-8. */ public class ConverterUtilTest extends TestCase { @Test public void testConvertFahrenheitToCelsius() throws Exception { } @Test public void testConvertCelsiusToFahrenheit() throws Exception { } }
修改文件ConverterUtilTest.java:
package com.vogella.android.temperatureconverter; import static org.junit.Assert.*; import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.vogella.android.temperatureconverter.ConverterUtil; public class ConverterUtilTest { @Test public void testConvertFahrenheitToCelsius() { float actual = ConverterUtil.convertCelsiusToFahrenheit(100); // expected value is 212 float expected = 212; // use this method because float is not precise assertEquals("Conversion from celsius to fahrenheit failed", expected, actual, 0.001); } @Test public void testConvertCelsiusToFahrenheit() { float actual = ConverterUtil.convertFahrenheitToCelsius(212); // expected value is 100 float expected = 100; // use this method because float is not precise assertEquals("Conversion from celsius to fahrenheit failed", expected, actual, 0.001); } }
配置Build Variants为unit test:
在左侧窗口单击
ConverterUtilTest.java, 在菜单栏选择"Run"->"Edit configuration", 配置Junit测试,这个窗口能够按ALT+Delete删除项目
更多参考资料:http://tools.android.com/tech-docs/unit-testing-support
执行:在左侧窗口右击
ConverterUtilTest.java, 选择 "Run ConverterUtilTest"。
Android的测试API提供钩子到Android的组件和应用生命周期。这些钩子即instrumentation API,它容许你的测试控制的生命周期和用户交互事件。
在正常状况下应用只反应生命周期和用户交互事件。例如Android的建立activity会调用onCreate()方法被调用您的活动。或用户按按钮或一个密钥和相应的代码被调用。经过instrumentation API这些事件。
InstrumentationTestRunner是Android测试的基础。它启动并加载测试方法。它经过instrumentation API与Android系统进行通讯。若是你开始Android应用测试,Android系统杀死被测应用,而后加载一个新的实例。它不启动应用程序,这是的测试方法的责任。测试方法控制的应用组件的生命周期。TestRunner初始化时调用应用和在正常状况下应用只反应生命周期和用户交互事件。例如Android的建立activity会调用onCreate的onCreate()方法 和活动的onCreate()方法。
通常是调用Espresso,不多直接使用 instrumentation API。
依赖配置:
defaultConfig { ..... more stuff testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } dependencies { // Unit testing dependencies androidTestCompile 'junit:junit:4.12' // Set this dependency if you want to use the Hamcrest matcher library androidTestCompile 'org.hamcrest:hamcrest-library:1.3' // more stuff, e.g., Mockito }
建议测试添加注解@RunWith(AndroidJUnit4.class)
。 AndroidJUnit4扩展JUnit4,纯Junit4语法和ActivityTestRule不是必需的。可是Espresso测试混合ActivityTestRule须要。gradle的执行方式“gradlew connectedCheck"。Android Studio的Build Variants窗口的设置以下:
要运行单元测试,应保证选择的是”Android Instrumentation Tests”,右击待测试的类而后选择”Run”。测试报告输出到 app/build/reports/androidTests/connected/,
index.html
是测试概述,它连接到单个测试页。
添加mockito支持:
dependencies { testCompile 'junit:junit:4.12' // required if you want to use Mockito for unit tests testCompile 'org.mockito:mockito-core:1.+' // required if you want to use Mockito for Android instrumentation tests androidTestCompile 'org.mockito:mockito-core:1.+' androidTestCompile "com.google.dexmaker:dexmaker:1.2" androidTestCompile "com.google.dexmaker:dexmaker-mockito:1.2" }
mockito彻底能够替代安卓原有的各类mock方法。mockito实例:
在上面例子增长Util类:
package com.vogella.android.temperatureconverter; import android.content.Context; import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.IOException; public class Util { public static void writeConfiguration(Context ctx) { BufferedWriter writer = null; try { FileOutputStream openFileOutput = ctx.openFileOutput("config.txt", Context.MODE_PRIVATE); openFileOutput.write("This is a test1.".getBytes()); openFileOutput.write("This is a test2.".getBytes()); } catch (Exception e) { throw new RuntimeException(e); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
增长测试类:
package com.vogella.android.temperatureconverter; import android.content.Context; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.io.FileOutputStream; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; public class TextContextOutputStream { @Mock Context context; @Mock FileOutputStream fileOutputStream; @Before public void init(){ MockitoAnnotations.initMocks(this); } @Test public void writeShouldWriteTwiceToFileSystem() { try { when(context.openFileOutput(anyString(), anyInt())).thenReturn(fileOutputStream); Util.writeConfiguration(context); verify(context, times(1)).openFileOutput(anyString(), anyInt()); verify(fileOutputStream, atLeast(2)).write(any(byte[].class)); } catch (Exception e) { e.printStackTrace(); fail(); } } }
参考资料:http://www.vogella.com/tutorials/AndroidTesting/article.html
http://www.sunmoonblog.com/blog/2015/06/10/android-testing/
Android 测试库的介绍参见:http://my.oschina.net/u/1433482/blog/602003。
Android testing API额外提供了MoreAsserts和ViewAsserts类。
注解@SmallTest, @MediumTest和@LargeTest可用于分组测试。Gradle支持选择部分分组执行测试,配置以下:
android { //.... defaultConfig { //.... testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArgument "size", "small" } }
注意Gradle 1.3.0之后支持,Android Studio在2015年还不支持。测试用例示例:
import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; import org.junit.Test; public class ExampleTest { @Test @SmallTest public void validateSecondActivity() { // Do something not so long... } @Test @MediumTest public void validateSecondActivityAgain() { // Do something which takes more time.... } }
注意上述代码不能执行。
测试过滤(Test filtering)主要针对须要依赖硬件或特殊SDK版本的测试。
注解@FlakyTest的tolerance属性能够配置重复测试的频率。
Activity的测试能够基于Espresso和UI Automator(https://pypi.python.org/pypi/uiautomator)。
Monkey是用于发送伪随机事件到您的设备的工具,能够指定软件包。例如,如下将发送2000随机事件到de.vogella.android.test.target包。
adb shell monkey -p de.vogella.android.test.target -v 2000
Monkey有时会致使adb server问题。使用如下命令从新启动ADB服务器。
adb kill-server adb start-server
您可使用-s [seed]参数,确保事件生成的序列老是相同的。
更多资料参见 http://developer.android.com/intl/zh-cn/tools/help/monkey.html
其余开源框架:Robolectric(推荐)、roboguice、Robotium。
Android运行时测试基于ApplicationTestCase类。期待谷歌推出安卓的JUnit4规则。
InstrumentationTestRunner初始化时自动建立实例,在onCreate方法作异步处理须要考虑。
微博 http://weibo.com/cizhenshi 做者博客:http://my.oschina.net/u/1433482/ python测试开发精华群 291184506 PythonJava单元白盒测试 144081101
本文英文原文:http://www.vogella.com/tutorials/AndroidTesting/article.html
由于后面部分基于junit3介绍为主,暂时不完整翻译。能够参考中文翻译:http://www.sunmoonblog.com/blog/2015/06/10/android-testing/