概述
Unit Test 和 Instrument Test 的区别
在 Android Developer 给出的 Instrument Test 解释如下:
Instrumented unit tests are unit tests that run on physical devices and emulators, instead of the Java Virtual Machine (JVM) on your local machine. You should create instrumented unit tests if your tests need access to instrumentation information (such as the target app’s Context) or if they require the real implementation of an Android framework component (such as a Parcelable or SharedPreferences object). Using instrumented unit tests also helps to reduce the effort required to write and maintain mock code. You are still free to use a mocking framework, if you choose, to simulate any dependency relationships. Instrumented unit tests can take advantage of the Android framework APIs and supporting APIs, such as the Android Testing Support Library。
简单的翻译: Instrumented Unit test 是允许在真机或者模拟器上的,而不是运行在本地环境下的虚拟机中。如果在测试时需要使用 instrumentation information(例如 app Context),或者你需要获取 Android 框架的组件(例如 SharedPrederences),这时候你就可以创建一个 instrumented unit test。使用 Instrumented unit test 可以帮助减少编写模拟环境的代码。当然你也可以使用一些 mock 框架。使用 Instrumented unit test 可以很好的利用 Android framework api 和 supporting API。
在 Android Developer 给出的 Local Unit Tests(Unit Test)解释如下:
If your unit test has no dependencies or only has simple dependencies on Android, you should run your test on a local development machine. This testing approach is efficient because it helps you avoid the overhead of loading the target app and unit test code onto a physical device or emulator every time your test is run. Consequently, the execution time for running your unit test is greatly reduced. With this approach, you normally use a mocking framework, like Mockito, to fulfill any dependency relationships.
简单的翻译:如果你的单元测试不依赖Android环境,那么你需要使用一个本地的单元测试,运行在本地的JVM上,这样的话,就有利于你的测试速度,因为加载物理设备是很耗费时间的。你可以使用类似于 Mockito 这种 Java 测试框架。
简单的总结一下是,这些情况适合用 Instrumented unit test :
- 测试时需要使用 Android api支持
- 测试时需要使用 Android 中的组件
- 测试时需要访问 Android 中的特定环境元素(例如 Context)
其他情况优先考虑使用 Unit Test ,因为它的速度要快很多,效率也要高很多。其次,Instrumented unit tes 是基于 Unit Test 的。所以我们先对 Unit Test 进行研究。
开始 Unit Test
概述
Local Unit Test 主要是基于 JUnit 4 test class。Junit 是 Android 中使用最广泛的单元测试框架,目前最新的版本是 Junit 4,不像之前的 Junit 3,你的单元测试类要继承junit.framework.TestCase,同时你的测试代码中,不会出现 junit.framework 和 junit.extensions 中的任何代码
配置 Android studio
查看版本
需要 Android Studio 1.1 以上 ,需要 Gradle Plugin 1.1.0-rc1 以上,AS的版本 在Help->About查看,Gradle Plugin 的版本在 File -> Project Structure->Project 查看
在 Module 下的 build.gradle 下添加必要的编译库,使用下面代码
dependencies {
testCompile ‘junit:junit:4.12’
testCompile “org.mockito:mockito-core:1.9.5”
}同步你的Project ( sync your project)
打开 unit Test
- 创建测试代码文件夹,在 src 下,可以创建如下代码文件夹 src/test/java ,此时文件夹名称会被标识为高亮绿色
高亮绿色是根据 Gradle 的单元测试约束来规定的,也就是说,你目前只能在 src/test/java 创建测试代码,如下我在其他文件夹,或者在test 目录下创建其他名称的文件夹,Gradle 是不会识别为 UNIT TEST的代码文件夹的。
编写测试代码
测试类代码 在 src/test/java/com/wbiao/util 下的 UTTest.java 中
package com.wbiao.util;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Created by Administrator on 2015/8/11.
*/
public class UTTest {
@Test
public void add(){
Assert.assertTrue(5== UT.add(2, 3));
}
@Test
public void mup(){
UT ut = new UT();
Assert.assertEquals(new Integer(12),new Integer(ut.mlutip(3,4)));
}
}
被测试代码
package com.wbiao.util;
/**
* Created by Administrator on 2015/8/11.
*/
public class UT {
//
//public static void printString(){
//System.out.println("I,m a test!");
//}
public static int add(int a,int b){
return a+b;
}
public int mlutip(int a,int b){
return a*b;
}
}
tip:需要在测试方法前需要添加 @Test 注解
两个知识点学习:
关于 Junit 4 中注解的使用:
- @Before 被这个注解的方法会阻塞 @Test 注解方法,在 @Test 注解方法前执行,如果存在多个 @Before 方法,执行顺序随机。这个注解的方法主要用来执行一些测试的设置。
- @After 被这个注解标志的方法,会在所有的 @Test 方法之后执行,主要用来释放资源的操作
- @Test 被这个注解标志的方法,就是你的测试方法,一个单元测试类可以有多个测试方法。
- @Test(timeout=) 带参数的 @Test 注解标签,如果方法在参数时间内没有成功完成,则返回失败。
- @BeforeClass 被这个标签标注的方法,会在Class第一次加载调用,所以你可以在里面执行一个 static 方法,比如一些 static 方法是很费资源的,例如 JDBC 操作。
- @AfterClass 对应着 @BeforeClass ,你可以进行一些 static 操作之后的资源释放。
Assert 系列方法的使用:
Junit 提供了一系列的 Assert 重载方法,提供你把预期结果(Object,long,Arrays 等类型)和实际结果进行比较。同时还有一个 AssertThat()方法,提供了一个失败 Message 的输出
tip:关于官方建议的命名规范,例如你想为src/main/java/com/wbiao/util 的 Util.java下的一个 add() 方法编写单元测试的代码,你可以在 src/test/java/com/wbiao/util/ 下编写 UtilTest.java 文件,然后编写 TestAdd() 方法来测试,这样的话是为了能让其他人更好的看懂你的代码。
关于测试框架
By default, the Android Plug-in for Gradle executes your local unit tests against a modified version of the android.jar library, which does not contain any actual code. Instead, method calls to Android classes from your unit test throw an exception.
官方的说明是,测试框架能减少对实际代码的依赖
使用官方推荐的 Mockito 框架
执行单元测试
配置执行环境
进入 Edit Configutate…
新增加一个 JUnit
然后对新加的 Junit 进行设置,至少需要设置 位置1 ,测试的目标类,和位置 2 测试的 module
配置完成之后,直接按运行的三角按钮就可以执行单元测试了
正确的单元测试结果
错误测试结果
使用 Gradle 进行 Unit Test
在右侧的 Gradle 面板,我们可以直接使用 Gradle 进行 单元测试构建,双击 Run Configurations ,然后会在 Run 的输出框,得到结果
点击运行
输出结果
打开 index.html
tip: 你可以在这个 index.html 页面看到许多相关的信息,在你使用了多组 Unit Test 测试的时候,效率要比直接在 AS 面板执行 Unit Test 要有效率。
在命令行执行 Unit Test
gradlew testDebug –tests=’*.MyTestClass’ (严重发现命令是错的,待确定)
gradlew test –continue
实际开发的问题
什么时候需要使用单元测试?
从单元测试的角度来说:单元测试的思路就是我们想在不涉及依赖关系的情况下测试代码. 这种测试可以让你无视代码的依赖关系去测试代码的有效性.核心思想就是如果代码按设计正常工作,并且依赖关系也正常,那么他们应该会同时工作正常.(将问题的研究集中在问题根本)
如何编写单元测试?
如果结合单元测试提高开发质量,加快开发速度,提高代码的鲁棒性?