单元测试
约 2095 字大约 7 分钟
2024-08-08
实战内容请移步 单元测试实战
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。
对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如 C 语 言中单元指一个函数,Java 里单元指一个类。总的来说,单元就是人为规定的最小的被测功能模块。
单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与 程序的其他部分相隔离的情况下进行测试。
单元测试的作用
单元测试有助于更早发现 bug,越早发现 bug,修复的成本越低。
1、保证或验证实现功能
2、保护已经实现的功能不被破坏
3、有助于回归测试
单元测试编写原则
单一职责:为每个接口单独编写用例,一个测试用例只针对一个接口的一个场景。
独立运行:测试用例之间彼此独立运行,互不影响。
覆盖率 :单元测试覆盖率是评判单元测试用例是否完备的重要指标,一般来说,业务代码覆盖率应该至少
80%,核心代码的 代码块覆盖率应尽量接近100%。在提测之前:单元测试应作为开发工作的一部分进行,代码交付测试前应完成单元测试的编写。
技术选型
Junit
JUnit 是一个 Java 编程语言的单元测试框架。JUnit 在测试驱动的开发方面有很重要的发展,是起源于 JUnit 的一个统称为 xUnit 的单元测试框架之一。JUnit 促进 了“先测试后编码”的理念,强调建立测试数据的一段代码,可以先测试,然后再应用
JUnit 是对 Java 进行单元测试时使用的基础框架,并得到各类开发工具和构建工具的 支持。实际使用时,主要用到 Junit 在单元测试的执行和断言方面的支持。
springboot2.2.0之前,spring-boot-starter-test默认支持的是junit4。springboot2.2.0之后,spring-boot-starter-test默认支持的是junit5。
Hamcrest
Hamcest 框架提供了一套匹配符 Matcher,这些匹配符更接近自然语言,可读性高,更 加灵活。
Hamcrest 提供了大量被称为“匹配器”的方法。其中每个匹配器都设计用于执行特定的比较操作。Hamcrest 的可扩展性很好,让你能够创建自定义的匹配器。最重要的是,JUnit 也包含了 Hamcrest 的核心,提供了对 Hamcrest 的原生支持,可以直接使用 Hamcrest。
断言
Hamcrest 结合匹配器进行断言,断言主要的方法是 org.hamcrest 包内的 MatcherAssert 类提供的,通常用方法 assertThat(断言描述,被断言对象,断言匹配 器)进行断言
SpringBootTest
SpringBootTest 通过 Spring-boot-starter-test 包引入。提供了对基于 SpringBoot 开发的项目的单元测试的支持。
DBUnit
DBUnit 提供了对单元测试的数据库表数据初始化和验证的支持。
@DatabaseSetup
@DatabaseSetup 注解用于配置单元测试前的数据初始化内容
| 配置 | 配置说明 | |
|---|---|---|
| value | value 配置的是用于初始化数据的 xml 数据文件路径 | |
| type | type 配置的是数据库操作方式 | |
| 先清空表中数据再插入() | ||
| UPDATE | 使用数据文件中的数据更新库中数据 | |
| INSERT | 使用数据文件中的数据插入库中数据 | |
| REFRESH | 使用数据文件中的数据刷新库中数据表,对于 库中已有的数据将使用文件中数据进行更新, 对于库中不存在的数据,将使用文件中的数据 插入数据表 | |
| DELETE | 从数据表中删除文件中存在的数据 | |
| DELETE_ALL | 从数据库中删除文件中涉及到的数据表的数 据,不影响未而配置在文件中的数据表 |
@ ExpectedDatabase
@ExceptedDatabase 注解用于配置单元测试完成后数据校验的标准
| 配置 | 配置说明 | |
|---|---|---|
| value | value 配置的是用于数据校验的数据文件路径,一般是 和测试类在一个包下 | |
| assertionMode | 校验模式(一般情况下都是采用 ) | |
| DEFAULT | 默认的校验模式,检查表中全部记录 | |
| NON_STRICT | 只允许指定预期数据集中的特定列和表。忽略未指定的表和列 | |
| NON_STRICT_UNORDERED | 只允许指定预期数据集中的特定列和表,而忽略预期和实际数据集中的行顺序。忽略未指定的表和列。忽略预期数据集和实际数据集中的执行顺序。 |
Xml 数据文件
DBUnit 以 XML 文件形式组织数据集。格式如下: idea有插件直接导出数据
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<user id="10000001" name="MaRui_1" />
<user id="10000002" name="MaRui_2" />
<user id="10000003" name="MaRui_3" />
</dataset>PowerMocktio
项目中调用第三方接口,大多都是线上真实环境,若每次真实调用会导致耦合,而且不符合测试原则,因此需要使用到 mock 工具,对接口进行模拟调用。
现如今比较流行的 Mock 工具如 jMock 、EasyMock 、Mockito 等都有一个共同的缺点:不能 mock 静态、final 、私有方法等。而 PowerMock 能够完美的弥补以上三个 Mock 工具的不足。
@Mock
如果测试中不需要用到容器中的东西,即所有都可以 Mock 注入,那 Mock 够用了,Mock 一般用在不依赖框架的单元测试
@MockBean
想要 mock 的类使用 @MockBean (如果有多个 bean,可以通过 name 属性来指定) ,其他的不想 mock 的直接不管,让 Spring 容器注入。
mock 使用
@Slf4j
public class UserControllerTest extends AbstractTest {
@MockBean
private DataCheckService dataCheckService;
@Test
public void testAdd1() throws Exception {
// Mock checkUser() 方法结果
Mockito.when(dataCheckService.checkUser(user)).thenReturn(Boolean.FALSE);
}
}MockMvc
MockMvc 是由 spring-test 包提供,实现了对 Http 请求的模拟,能够直接使用网络的形式,转换到 Controller 的调用,使得测试速度快、不依赖网络环境。同时提供了一套验证的工具,结果的验证十分方便。
接口 MockMvcBuilder,提供一个唯一的 build 方法,用来构造 MockMvc。主要有两个实现:StandaloneMockMvcBuilder 和 DefaultMockMvcBuilder,分别对应 两种测试方式,即独立安装和集成 Web 环境测试(并不会集成真正的 web 环境,而是 通过相应的 Mock API 进行模拟测试,无须启动服务器)
MockMvcBuilders 提供了对应的创建方法 standaloneSetup 方法和 webAppContextSetup 方法,在使用时直接调用即可。
| 实例化方法 | |
|---|---|
| standaloneSetup | mockMvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build(); |
| webAppContextSetup | mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); |
使用步骤
1、
mockMvc.perform执行一个请求2、
MockMvcRequestBuilders.get(“XXX”)构造一个请求3、
ResultActions.param添加请求传值4、
ResultActions.accept()设置返回类型5、
ResultActions.andExpect添加执行完成后的断言6、
ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情,比如处使用print()输出整个响应结果信息7、
ResultActions.andReturn表示执行完成后返回相应的结果
H2 内嵌式数据库
H2 是一个用 Java 开发的嵌入式数据库,它本身只是一个类库,可以直接嵌入到应用项目中。
1、在于可以同应用程序打包在一起发布,这样可以非常方便地存储少量结构化数据。
2、它的另一个用途是用于单元测试。启动速度快,而且可以关闭持久化功能,每一个用例执 行完随即还原到初始状态。
3、
H2的第三个用处是作为缓存,作为NoSQL的一个补充。
测试任意的 bean
单元测试所需依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>测试任意 bean 示例代码
/**
* @ClassName StaticProxyTest
* @Desciption 代理模式测试
* @Author MaRui
* @Date 2022/9/28 16:57
* @Version 1.0
*/
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class ProxyTest {
/**
* 静态代理测试
*/
@Test
public void testStaticProxy() {
SmsServiceImpl smsService = new SmsServiceImpl();
SmsProxy smsProxy = new SmsProxy(smsService);
smsProxy.send("hello呀");
}
}