一. 前言
单元测试并不只是为了验证你当前所写的代码是否存在问题,更为重要的是它可以很大程度的保障日后因业务变更、修复Bug或重构等引起的代码变更而导致(或新增)的风险。
同时将单元测试提前到编写正式代码进行(测试驱动开发),可以很好的提高对代码结构的设计。通过优先编写测试用例,可以很好的从用户角度来对功能的分解、使用过程和接口等进行设计,从而提高代码结构的高内聚、低耦合特性。使得对日后的需求变更或代码重构等更加高效、简洁。
因此编写单元测试对产品开发和维护、技术提升和积累具有重大意义!
二. 第一个单元测试
首先写一个单元测试,这样有助于对后面内容的理解与实践。
2.1 开发环境
**IntelliJ IDEA **
IntelliJ IDEA默认自带并启用TestNG和覆盖率插件:
TestNG
在设置窗口查看TestNG插件是否安装与启用:
覆盖率
同样,查看覆盖率插件可以搜索“Coverage”。IntelliJ IDEA的覆盖率统计工具有三种,JaCoCo、Emma和IntelliJ IDEA自带。
变异测试
同样,查看并安装变异测试插件可以搜索“PIT mutation testing”。
**Eclipse **
Eclipse需要自行安装单元测试相关插件:
TestNG
执行TestNG单元测试的插件。可在Eclipse Marketplace搜索“TestNG”安装:
覆盖率
获取单元测试覆盖率的插件。可在Eclipse Marketplace搜索“EclEmma”安装:
变异测试
同样,查看并安装变异测试插件可以搜索“Pitclipse”。
2.2 Maven依赖
TestNG
org.testng
testng
${testng.version}
test
JMockit
org.jmockit
jmockit
${jmockit.version}
test
org.jmockit
jmockit-coverage
${jmockit.version}
test
Spring Test
org.springframework
spring-test
${spring.version}
test
org.kubek2k
springockito
${springockito.version}
test
org.kubek2k
springockito-annotations
${springockito.version}
test
其他(或许需要)
org.apache.tomcat
tomcat-servlet-api
${tomcat.servlet.api.version}
test
2.3 创建单元测试
下面介绍通过IDE自动创建单元测试的方法(也可手动完成):
IntelliJ IDEA
Eclipse:
2.在弹出的窗口中搜索“Test”,选择“TestNG class”后点击“Next”按钮:
3.在窗口中选择要创建的测试方法后点击“Next”按钮:
4.根据自己的情况设置包名、类名和Annotations等:
示例代码
可参考下例代码编写单元测试:
package org.light4j.unit.test;
import mockit.Expectations;
import mockit.Injectable;
import mockit.Tested;
import org.testng.Assert;
import org.testng.annotations.Test;
import wow.unit.test.remote.UserService;
import java.util.List;/**
* 单元测试demo
*
* @author jiazuo.ljz*/
public classBookServiceTest {/**
* 图书持久化类,远程接口*/@InjectableprivateBookDAO bookDAO;/**
* 用户服务,远程接口*/@InjectableprivateUserService userService;/**
* 图书服务,本地接口*/@Tested(availableDuringSetup= true)privateBookService bookService;/**
* 测试根据用户的Nick查询用户的图书列表方法
* 其中“getUserBooksByUserNick”方法最终需要通过UserID查询DB,
* 所以在调用此方法之前需要先对UserService类的getUserIDByNick方法进行Mock。*/@Testpublic voidtestGetUserBooksByUserNick() throws Exception {newExpectations() {
{
userService.getUserIDByNick(anyString);//Mock接口
result = 1234567; //Mock接口的返回值
times = 1; //此接口会被调用一次
}
};
List bookList = bookService.getUserBooksByUserNick("moyuan.jcc");
Assert.assertNotNull(bookList);
}
}
2.4 运行单元测试
IntelliJ IDEA
Eclipse
注:也可点击工具栏选项运行,从左至右依次是:覆盖率、调试、运行运行。
2.点击“运行”:
左侧框:单元测试运行结果
底侧框:单元测试打印输出的内容
Maven
执行目录下所有单元测试,进入工程目录后执行:mvn test
执行具体的单元测试类,多个测试类可用逗号分开:mvn test -Dtest=Test1,Test2
执行具体的单元测试类的方法:mvn test -Dtest=Test1#testMethod
执行某个包下的单元测试:mvn test -Dtest=com/alibaba/biz/*
执行ANT风格路径表达式下的单元测试:mvn test -Dtest=/Test或mvn test -Dtest=*/???Test
忽略单元测试:mvn -Dmaven.test.skip=true
2.5 单元测试覆盖
IntelliJ IDEA
Eclipse
2.输出报告
运行过程以及结果输出的窗口中有一行“JMockit: Coverage report written to”,是EclEmma创建的覆盖率报告文件目录:
覆盖率报告
2.6 变异测试
变异测试是覆盖率的一个很好的补充。相比覆盖率,它能够使单元测试更加健壮。(具体可见5.4节)
IntelliJ IDEA