确定单元测试方案
本次实验利用一个计算器程序代码作为 Java 单元测试的对象,选用 Eclipse 作为 Java 开发工具,下载并安装 JUnit 和 JaCoCo 工具,使用 JUnit 进行单元测试,使用 JaCoCo 进行覆盖率分析来辅助进行单元测试。
创建实验项目
在 Eclipse 里新建一个 Java 工程(File->New->Project),取名为 JUnitDemo,然后新建一
个名叫 Number 的类,包的名称叫做 my.demo:
接下来给这个 Number 类添加一些测试方法,为了简单起见,这里以除法作为例子:
package my.demo;
public class Number {
public int division(int a,int b) {
return a/b;
}
}
引入 JUnit 至工程
这里先将 JUnit 所需的 jar 包引入项目(Eclipse 自带 JUnit 的 jar 包)。右键单击我们刚才
创建的项目->Build Path->Add Libraries:
选择 Add Library 对话框中的 JUnit,点击下方的 Next 按钮,再选择 JUnit 4 即可:
创建测试类
右键选择待测试的类文件(这里是 Number.java)->New->Other,在新弹出的 New 对话
框中,选择 JUnit Test Case,然后点击 Next:
在新弹出的 New JUnit Test Case 对话框中,选择 Next,然后勾选整个 Number 类:
于是就会发现项目中多了一个名为 NumberTest.java 的测试类:
JUnit 的“断言”
使用 JUnit 进行测试,使用的是“断言”来进行测试。断言是编写测试用例的核心实现
方式,即对比期望值和测试的结果是否相同,以此来判断测试是否通过。断言的核心方法有
以下几种:
注解
注解与注释不同,注释是由“//”等开头,而注解是“@”开头。两者的区别是注释不
会对程序本身有任何影响,其作用仅仅是方便我们更好的理解代码。而注解是对程序本身又
影响的,它相当于是一个可执行的代码。JUnit 常用注解及其作用有:
编写测试代码
这里我们采用 assertEquals(excepted, actual)来进行举例:
如果我们想要测试单独的某个方法,需要右键该方法->Run as->JUnit Test;如果是想要测试一个类中的全部方法,则右键类名->Run as ->JUnit Test,之后会出现一个测试窗体,如果全部是绿条,则表明所测试的对象是无误的,测试成功:
错误案例
当绿条变成红色的时候,代表测试对象有误,其中包括两种错误,一个是 Failure,另一个是 Error。Failure 的出现代表程序运行的实际值和预期值不符,而 Error 的出现代表代码本身有误或者有隐藏的 bug。
这里我们编写了两个错误代码,一个是测试 8 除以 4 是否等于 3,另一个是测试 6 除以0 是否等于 1。下方的测试框中显示了测试结果,一个 Failure,一个是 Error:
Failure 方法的错误描述是 java.lang.AssertionError: expected:<3> but was:<2>,表示预期是 3,但实际值是 2。
Error 的错误描述是 java.lang.ArithmeticException: / by zero。意思是除数不能是 0。
JaCoCo 的下载、安装与使用
JaCoCo是一个开源的覆盖率分析工具,可以帮助大家在单元测试时分析代码覆盖情况。
可从网站 https://www.eclemma.org/download.html 中下载 JaCoCo 的 Eclipse 插件 EclEmma 的
最新版本,本实验中使用的版本是 eclemma-3.1.2。
解压 eclemma-3.1.2.zip 到 Eclipse 安装路径下的 dropins 目录中,并且仅保留如下图所示
的文件和文件夹:
打开 Eclipse,在工具栏的 Help 菜单中选择 Install New Software,在 Install 窗口中单击
Add 按钮,并在 Local 的弹出框中选择 EclEmma 所在的路径,并为其取一个名字进行添加:
安装好以后,就可以在单元测试的基础上进行覆盖率的实验。同样选择已进行过单元测试的 NumberTest.java 文件,右键单击该文件后,选择菜单 Coverage As->JUnit Test。
如果与预期相符,JUnit 标签的界面会出现绿色的提示条,若失败则会出现红色提示条,同样也会提示失败原因和代码行。
打开被测代码 Number.java 文件,会发现 division()方法整个用绿色标示了,代表此段代码的所有分支全部被覆盖,其它未被覆盖的方法则用红色进行标示:
并且,在 Coverage 标签页面有覆盖率的统计,可以看到图中的 Number.java 类文件的覆盖率为 100%,其方法 division(int,int)的覆盖率也是 100%。
举一反三,接下来为大家演示加法、减法和乘法。
方法addition(int,int)
对方法addition(int,int)进行单元测试
加法:
成功案例:
失败案例:
对方法addition(int,int)进行覆盖率实验:
结果分析:
由图可看出Number.java类文件的覆盖率为100%,其方法addition(int,int)的覆盖率也是100%。
方法subtraction(int,int)
对方法subtraction(int,int)进行单元测试
减法:
成功案例:
失败案例:
对方法subtraction(int,int)进行覆盖率实验:
结果分析:
由图可看出Number.java类文件的覆盖率为100%,其方法subtraction(int,int)的覆盖率也是100%。
方法multiplication(int,int)
对方法multiplication(int,int)进行单元测试
乘法:
成功案例:
失败案例:
对方法multiplication(int,int)进行覆盖率实验:
结果分析:
由图可看出Number.java类文件的覆盖率为100%,其方法multiplication(int,int)的覆盖率也是100%。
结果分析与总结
本实验主要是通过添加补充方法或类的单元测试代码进行单元测试和覆盖率检查,分析单元测试是否正常进行以及被测代码中的条件分支是否被全部覆盖。本实验的重难点在于对JUnit、EclEmma 工具的使用,以及对单元测试的正确理解。
JUnit的特点:
JUnit提供了注释以及确定的测试方法;
JUnit提供了断言用于测试预期的结果;
JUnit测试优雅简洁不需要花费太多的时间;
JUnit测试让大家可以更快地编写代码并且提高质量;
JUnit测试可以组织成测试套件包含测试案例,甚至其他测试套件;
Junit显示测试进度,如果测试是没有问题条形是绿色的,测试失败则会变成红色;
JUnit测试可以自动运行,检查自己的结果,并提供即时反馈,没有必要通过测试结果报告来手动梳理。