0%

单元测试笔记

前言

最近写很多单元测试 一直没记录
今天整理一下 常见的demo 方便后续速查

https://junit.org/junit5/docs/current/user-guide/#overview

JUnit5注解汇总

基础测试控制
注解 含义 使用场景
@Test 标记测试方法 单个测试逻辑的验证
@BeforeEach 每个测试方法前执行 初始化测试环境
@AfterEach 每个测试方法后执行 清理测试环境
@BeforeAll 整个测试类执行前运行 初始化全局资源
@AfterAll 整个测试类执行后运行 清理全局资源
@Disabled 禁用测试方法 暂时跳过测试
@Tag 标记测试,支持按标签执行 组织和筛选测试
@DisplayName 设置显示名称 提高测试输出可读性
参数化测试
注解 含义 使用场景
@ParameterizedTest 参数化的测试 验证不同输入值的行为
@ValueSource 提供固定值作为参数 参数列表
@EnumSource 提供枚举值作为参数 枚举遍历
@CsvSource / @CsvFileSource CSV数据作为参数 数据驱动测试
测试控制和异常测试
注解 含义 使用场景
@RepeatedTest 重复执行测试 验证稳定性
@AssertThrows 验证方法抛出预期异常 异常处理测试
扩展和定制
注解 含义 使用场景
@TestExtension 定义测试扩展 自定义测试行为
@RegisterExtension 注册测试扩展 使用自定义扩展
@TempDir 提供临时目录 存储临时文件
@Import 引入额外配置类 测试上下文扩展

mockito

注解 作用 使用场景
@Mock 创建一个模拟对象,可以控制其行为和返回值。 当需要隔离测试,不依赖真实对象时。
@Spy 创建一个真实对象的代理,可以部分模拟,其他行为保持不变。 当需要测试部分真实行为,同时控制某些方法时。
@InjectMocks 自动注入依赖,通常用于创建被测试对象,其中依赖项由@Mock@Spy注解的实例填充。 当测试类需要依赖模拟对象时。
@Captor 配合ArgumentCaptor使用,捕获方法调用的参数。 当需要验证方法调用的参数时。
@RunWith(MockitoJUnitRunner.class) 使用Mockito运行器,初始化@Mock@Spy注解的实例。 在JUnit测试类中使用,代替@Before初始化模拟对象。
@Before 初始化方法,通常用于配置模拟对象。 需要在每个测试方法之前执行的初始化逻辑。
@After 清理方法,通常用于清理模拟对象。 需要在每个测试方法之后执行的清理逻辑。
@MockBean Spring Boot测试中创建模拟的Spring Bean。 当测试需要模拟Spring容器中的Bean时。
@SpyBean Spring Boot测试中创建真实Bean的代理,可以部分模拟。 当测试需要部分模拟Spring容器中的Bean时。
@WithMockUser Spring Security测试中模拟登录用户的身份。 当测试需要模拟不同用户权限时。
@MockitoSettings 控制Mockito框架的全局设置,如严格性、默认答案等。 当需要自定义Mockito的行为时。
@ExtendWith(MockitoExtension.class) JUnit 5中初始化Mockito,替代@RunWith(MockitoJUnitRunner.class) 在JUnit 5测试类中使用。
Mockito 主要类和函数
Mockito 类与函数
类名 函数 描述
Mockito mock(Class<T> classToMock) 创建模拟对象,不执行实际操作。
when(T toMock) 定义模拟对象的行为,设置方法调用的返回值或行为。
thenReturn(T value) 模拟方法调用时返回指定值。
thenThrow(Throwables... toThrow) 模拟方法调用时抛出异常。
doAnswer(Answer answer) 自定义方法调用的处理逻辑。
doNothing() 方法调用不执行任何操作,不返回值。
doCallRealMethod() 使模拟方法调用实际实现。
verify(T mock) 验证模拟对象的方法是否被调用。
verifyNoMoreInteractions(Object... mocks) 验证没有其他未验证的交互。
verifyZeroInteractions(Object... mocks) 验证模拟对象未被调用。
ArgumentMatchers 辅助类
函数 描述
any() 匹配任何参数值。
anyVararg() 匹配任何变长参数。
eq(T value) 匹配与给定值相等的参数。
Assertions 主要方法
JUnit Jupiter (org.junit.jupiter.api.Assertions)
方法 描述
assertEquals(expected, actual) 验证预期值与实际值相等。
assertNotEquals(expected, actual) 验证预期值与实际值不相等。
assertTrue(condition) 验证条件为真。
assertFalse(condition) 验证条件为假。
assertNull(object) 验证对象为 null。
assertNotNull(object) 验证对象非 null。
assertSame(expected, actual) 验证预期对象与实际对象是同一个对象。
assertNotSame(expected, actual) 验证预期对象与实际对象不是同一个对象。
assertAll(Executable... executables) 批量执行多个断言。

示例

  • 基本依赖 starter包包含了 junit5和mockito
1
testImplementation "org.springframework.boot:spring-boot-starter-test"
  • 基本单元测试格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.ming;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
public class DemoTest {
@BeforeEach
public void init() {
System.out.println("init");
}

@AfterEach
public void destroy() {
System.out.println("destroy");
}

@Test
public void test() {
System.out.println("test");
}
}
  • mock静态方法

mock静态方法 以前是用powermock junit5之后 mockito也提供mock的方式

1
2
// https://mvnrepository.com/artifact/org.mockito/mockito-inline
testImplementation group: 'org.mockito', name: 'mockito-inline', version: '5.2.0'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;

@ExtendWith(SpringExtension.class)
public class MockStaticTest {
private MockedStatic<StaticTestService> mockStatic;
@BeforeEach
public void setUp() {
mockStatic = org.mockito.Mockito.mockStatic(StaticTestService.class);
}

@AfterEach
public void tearDown() {
mockStatic.close();
}

@Test
public void testNoArg() {
mockStatic.when(StaticTestService::testNoArg).thenReturn("test");
assertEquals("test", StaticTestService.testNoArg());
}

@Test
public void testArg() {
mockStatic.when(() -> StaticTestService.testArg("arg")).thenReturn("test");
assertEquals("test", StaticTestService.testArg("arg"));
assertNotEquals("test", StaticTestService.testArg("arg1"));
}
}

class StaticTestService {
public static String testNoArg() {
return "????";
}

public static String testArg(String str) {
return "????";
}
}
  • mock私有变量

ReflectionTestUtils.setField(testService, “字段名”, “字段赋值”);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.util.ReflectionTestUtils;

import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(SpringExtension.class)
public class MockTest {
@InjectMocks
private TestService testService;

@Test
public void test() {
assertEquals("????ming-default", testService.getStr());
ReflectionTestUtils.setField(testService, "str", "ming-update");
assertEquals("????ming-update", testService.getStr());
}
}

class TestService {
private String str = "ming-default";

public String getStr() {
return "????" + str;
}
}
  • mock MybatisPlus Mapper

    如果用到lambdaXXXXX 需要注入 TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), “”), xxxxEntity.class);

总结

就是常见的单元测试方法
junit5 已经成为一个java的单元测试平台了
常见的操作 基本覆盖
配合mockito基本够用