单元测试
单元测试的作用
基本作用
(1)使代码可以放心修改和重构;
(2)迫使程序员从调用者而不是实现者的角度设计软件模块;
(3)迫使程序员将软件模块写得易于测试和调用,从而有利于解耦;
(4)测试本身可作为被测代码的用法说明,从而替代了一部分文档功能。
来自网络,其可自由搜索。
个人补充
单元测试是开发编码的一部分,不是补充、不是锦上添花。
CD/CI的基本技术要求。
单元测试需要的编程基础
面向对象的设计与开发能力,熟悉基本OO原则:单一职责、开闭
设计模式基本运用。
去除各种编码的陋习:命名混乱,类职责过多等。
参考书:Junit In Action,重构(马丁 福勒)
主要测试框架
基本框架:Junit/TestNG
Mock框架:Jmockit,Mockito,PowerMock等
本次讲解使用 Junit ,Jmockit.( http://jmockit.github.io/)
Junit:基本单元测试框架
Jmockit:使用-javaagent参数改写代码,完成各种测试。
环境配置
准备工作主要有:引入junit和jmockit的jar包,配置jmockit的执行参数
Maven
加入依赖:
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>${jmockit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
配置执行参数
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<reuseForks>true</reuseForks>
<forkCount>3</forkCount>
<argLine>-javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar -Dfile.encoding=UTF-8</argLine>
<systemPropertyVariables>
<jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
<executions>
<execution>
<id>run-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skip>false</skip>
<includes>
<include>**/**/*Test*.java</include>
</includes>
<excludes>
<exclude>**/*IT.java</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
Gradle
加入依赖:
testCompile("org.jmockit:jmockit:1.45")
testCompile group: 'junit', name: 'junit', version: '4.12'
配置执行参数
test {
jvmArgs "-javaagent:${classpath.find { it.name.contains("jmockit") }.absolutePath}"
exclude '**/*/BaseTest.class'
exclude '**/*/BaseSpringBootTest.class'
}
可选依赖
hamcrest-core.jar,增加断言的一致性,简化断言语句。
基础测试用例
基本原则
CUT:待测试代码。
1.CUT的基本单位是类和方法,不是面向用户或者客户端的功能。
2.尽量少编写带有环境的测试代码和CUT。
带环境的测试用例(执行速度慢)保持在总用例数的20%以内。大型工程的此类用例可能单独执行。
测试时执行的CUT需要尽量减少外部依赖(自己写的组件、类),尽可能的只测试改方法的主要功能。
简单示例
网上抄的:
Caculate.java:
CaculateTest.java:
使用Jmockit
待测代码
测试代码
基于SpringBoot的测试
基本原则
建议控制用例数量在总数量的20%以内,尽量少用。
创建统一配置的测试基础类,可重用TestContext,节省环境初始化的时间。
环境配置
增加Springboot测试依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${springboot.version}</version>
<scope>test</scope>
</dependency>
测试数据库依赖(h2database)
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.199</version>
<scope>test</scope>
</dependency>
测试的超类
@RunWith(SpringRunner.class)
@SpringBootTest
@Ignore
@Transactional
public class BaseSpringBootTest{
}
创建数据库结构和初始化数据的测试辅助配置类
数据库初始化脚本文件(sql/*.sql)和应用配置文件(application.yml)
用例示例
ModelQueryServiceTest.java
反例
StandardVocabularyServiceImpl.java,关注moreFieldGeneration方法(代码生成功能的原始版本)。
问题:职责过多;代码太长;命名不明确。