一. 前言
单元测试并不只是为了验证你当前所写的代码是否存在问题,更为重要的是它可以很大程度的保障日后因业务变更、修复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
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
- JMockit
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>${jmockit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit-coverage</artifactId>
<version>${jmockit.version}</version>
<scope>test</scope>
</dependency>
- Spring Test
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.kubek2k</groupId>
<artifactId>springockito</artifactId>
<version>${springockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.kubek2k</groupId>
<artifactId>springockito-annotations</artifactId>
<version>${springockito.version}</version>
<scope>test</scope>
</dependency>
- 其他(或许需要)
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>${tomcat.servlet.api.version}</version>
<scope>test</scope>
</dependency>
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 class BookServiceTest {
/**
* 图书持久化类,远程接口
*/
@Injectable
private BookDAO bookDAO;
/**
* 用户服务,远程接口
*/
@Injectable
private UserService userService;
/**
* 图书服务,本地接口
*/
@Tested(availableDuringSetup = true)
private BookService bookService;
/**
* 测试根据用户的Nick查询用户的图书列表方法
* 其中“getUserBooksByUserNick”方法最终需要通过UserID查询DB,
* 所以在调用此方法之前需要先对UserService类的getUserIDByNick方法进行Mock。
*/
@Test
public void testGetUserBooksByUserNick() throws Exception {
new Expectations() {
{
userService.getUserIDByNick(anyString); // Mock接口
result = 1234567; // Mock接口的返回值
times = 1; // 此接口会被调用一次
}
};
List<BookDO> 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 -Dte