单元测试
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呀");
}
}