参考文献
https://github.com/jdqm/AndroidUnitTest
备注:以下文章集合了上面两者抄过来的
什么是单元测试?
单元测试就是针对类中的某一个方法进行验证是否正确的过程,单元就是指独立的粒子,在Android和Java中大都是指方法。
这里也带来了一个思考,如果针对一个页面的测试算不算单元测试???
为什么要进行单元测试?
使用单元测试可以提高开发效率,当项目随着迭代越来越大时,每一次编译、运行、打包、调试需要耗费的时间会随之上升,因此,使用单元测试可以不需这一步骤就可以对单个方法进行功能或逻辑测试。
同时,为了能测试每一个细分功能模块,需要将其相关代码抽成相应的方法封装起来,这也在一定程度上改善了代码的设计。因为是单个方法的测试,所以能更快地定位到bug。
单元测试case需要对这段业务逻辑进行验证。在验证的过程中,开发人员可以深度了解业务流程,同时新人来了看一下项目单元测试就知道哪个逻辑跑了多少函数,需要注意哪些边界——是的,单元测试做的好和文档一样具备业务指导能力。
单元测试的分类
1.本地测试(Local tests): 只在本地机器JVM上运行,以最小化执行时间,这种单元测试不依赖于Android框架,或者即使有依赖,也很方便使用模拟框架来模拟依赖,以达到隔离Android依赖的目的,模拟框架如google推荐的Mockito;
2.仪器化(UI)测试(Instrumented tests): 在真机或模拟器上运行的单元测试,由于需要跑到设备上,比较慢,这些测试可以访问仪器(Android系统)信息,比如被测应用程序的上下文,一般地,依赖不太方便通过模拟框架模拟时采用这种方式。
这里src目录下有三个文件夹:androidTest( UI测试),main(业务逻辑开发),test(本地测试,仪器化测试),当前三个目录都是android studio自动生成,并且Junit是创建项目时自动就引入进来的,如下gradle里面的代码
testImplementation 'junit:junit:4.12'
一、单元(src/test目录下:本地测试)测试之基础Junit4
什么是Junit4?
Junit4是事实上的Java标准测试库,并且它是JUnit框架有史以来的最大改进,其主要目标便是利用Java5的Annotation特性简化测试用例的编写。
了解一些JUnit注解,有助于更好理解后续的内容:
主要的测试方法——断言
- assertEquals(expected, actual) 判断2个值是否相等,相等则测试通过。
- assertEquals(expected, actual, tolerance) tolerance 偏差值
学习与实战
1.超时(单位是毫秒)
Junit 提供了一个指定超时参数。如果一个测试用例执行的毫秒数超过了指定的参数值,那么 Junit 将自动将它标记为失败。
public class ExampleUnitTest {
@Test(timeout = 200)
public void addition_isCorrect() {
Sleep sleep = new Sleep();
sleep.setMilliseconds(1000);
sleep.execute();
int i = 0 + 1;
assertEquals(4, 2 + 2);
System.out.println(i + "");
}
}
如下所示,当我执行睡眠了1000毫秒,执行报错错误发生在230ms,错误代码在20行:sleep.execute();
实际引用中作用并不是很大,因为我们执行的时间以及在上面显示了,下图表示执行成功后的状态显示,上图同样的地方显示执行失败是的显示状态
2.捕获异常
Junit 提供了一个捕获异常的参数。你可以测试代码是否抛出了预期的异常。
package com.example.androidtest;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test(expected = ArithmeticException.class)
public void addition_isCorrect() {
// assertEquals(4, 2 + 2);
int a = 0;
int b = 1/a;
}
}
有作用吗!!!不加expected不香吗
3.参数化(重要)
Junit 4 引入了一个新的功能参数化测试。参数化测试允许开发人员使用不同的值反复运行同一个测试。你可以遵循下面的步骤来创建参数化测试。
- 在测试类上添加注解@RunWith(Parameterized.class)。
- 创建一个由 @Parameters 注解的公共的静态方法,它返回一个对象的集合(数组)来作为测试数据集合。
- 创建一个公共的构造函数,参数个数和类型与提供的数据集合一一对应。
- 为每一列测试数据创建一个实例变量。(这个是在@Before中完成,对照下面代码看)
- 用实例变量作为测试数据的来源来创建你的测试用例。
demo:
在src/main/java模块新建一个CheckNumberIsPlural 类,用于检查传入的数字是否复数
package com.example.androidtest;
/**
* Copyright (C), 2019-2020, 佛生
* FileName: CheckNumberIsPlural
* Author: 佛学徒
* Date: 2020/11/12 9:28
* Description: 检查数字是否是复数
* History:
*/
public class CheckNumberIsPlural {
public static Boolean checked(int number) {
if (number % 2 == 0)
return true;
return false;
}
}
针对CheckNumberIsPlural 创建一个test类,我们将鼠标移动到类名上,按住alt+enter,然后出现Create Test,点击
如下图所示,Testing library选择 JUnit4 , Generate选中 setUp/@Before,这个方法一般用于test之前的对象实例化(这里不选代码中也可以自己添加)
因为JUnit是本地测试,所以生成的Test文件应该存放在src/test文件夹下
package com.example.androidtest;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Copyright (C), 2019-2020, 佛生
* FileName: CheckNumberIsPluralTest
* Author: 佛学徒
* Date: 2020/11/12 9:37
* Description:
* History:
*/
public class CheckNumberIsPluralTest {
@Before
public void setUp() throws Exception {
}
@Test
public void checked() {
}
}
然后自己添加:
package com.example.androidtest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.*;
/**
* Copyright (C), 2019-2020, 佛生
* FileName: CheckNumberIsPluralTest
* Author: 佛学徒
* Date: 2020/11/12 9:37
* Description:
* History:
*/
@RunWith(Parameterized.class)
public class CheckNumberIsPluralTest {
private int number;
private Boolean isPlural;
private CheckNumberIsPlural checkNumberIsPlural;
@Before
public void setUp()