技术栈:junit5+mockito+inline-mockito+jdk8
1.注解
1.1 JUnit 5 注解
注解 | 说明 |
---|---|
@Test |
声明测试方法 |
@BeforeEach |
每个测试方法执行前运行 |
@AfterEach |
每个测试方法执行后运行 |
@BeforeAll |
所有测试方法前运行,需为static |
@AfterAll |
所有测试方法后运行,需为static |
@DisplayName |
给测试类或方法命名(更友好的描述) |
@Nested |
嵌套测试类 |
@Disabled |
禁用测试类或方法 |
@Tag |
分组标签(可用于筛选测试) |
@ParameterizedTest |
参数化测试 |
1.1.1 @Test
在 JUnit 5 中,@Test 是最基本、最常用的注解之一,用于标识一个方法为测试方法,由 JUnit 引擎在运行测试时自动执行。 Demo:
java
import org.junit.jupiter.api.Test;
class MyServiceTest {
@Test
void testAddition() {
int result = 2 + 3;
assertEquals(5, result);
}
}
📘 @Test
注解的核心特点
特性 | 说明 |
---|---|
来自包 | org.junit.jupiter.api.Test (JUnit 5 Jupiter) |
返回类型 | 测试方法必须是 void (不能有返回值) |
方法签名 | 可以是 private 、default 、public ,推荐使用 default 或 public |
方法参数 | 默认不接受参数(除非使用扩展机制) |
抛出异常 | 方法可以抛出异常,如 throws Exception |
1.1.2 @BeforeEach
在 JUnit 5 中,@BeforeEach
注解用于指定一个在每个测试方法执行之前都会执行的方法。它常用于初始化测试环境,例如重置对象状态、配置依赖项等。
✅ 基本语法
java
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class MyServiceTest {
private MyService service;
@BeforeEach
void setUp() {
service = new MyService(); // 每次测试都会重新创建
}
@Test
void test1() {
assertNotNull(service);
}
@Test
void test2() {
assertNotNull(service);
}
}
每次执行 test1()
和 test2()
前,都会先调用 setUp()
。
📘 关键特性
特性 | 说明 |
---|---|
来源 | org.junit.jupiter.api.BeforeEach |
方法修饰符 | 可以是 public 、protected 、package-private (不强制是 public ) |
方法签名 | 必须是无参、返回 void 的实例方法 |
执行顺序 | 每个 @Test 执行前都调用一次 |
可继承性 | 如果在父类中定义 @BeforeEach ,子类也会调用(类似模板方法) |
✅ 常见用途
- 初始化被测试对象
- 重置 mock 对象
- 构建测试数据
- 日志打印或资源准备
1.1.3 @BeforeAll
在 JUnit 5 中,@BeforeAll
注解用于在所有测试方法执行之前运行一次的初始化逻辑。它通常用于耗时较高的全局资源准备,比如建立数据库连接、加载配置文件、启动服务模拟器等。
✅ 基本使用
java
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
class MyServiceTest {
@BeforeAll
static void initAll() {
System.out.println("初始化资源,仅执行一次");
}
@Test
void test1() {
System.out.println("测试 1");
}
@Test
void test2() {
System.out.println("测试 2");
}
}
🟡 输出顺序:
初始化资源,仅执行一次
测试 1
测试 2
📘 特性一览
特性 | 说明 |
---|---|
执行时机 | 所有测试类中的测试方法执行前,只调用一次 |
方法修饰符 | 默认要求是 static 方法 |
方法签名 | 无参数、返回 void |
异常处理 | 可以 throws Exception |
注解包路径 | org.junit.jupiter.api.BeforeAll |
✅ @BeforeAll
与 @BeforeEach
对比
注解 | 调用频率 | 是否可为非 static |
---|---|---|
@BeforeAll |
所有测试前一次 | 否(默认);加 @TestInstance(PER_CLASS) 可支持 |
@BeforeEach |
每个测试方法前 | 是,默认是实例方法 |
🎯 常见用途
- 启动嵌入式数据库(如 H2、TestContainers)
- 初始化共享资源或配置
- Mock 框架预设环境(如全局 token、认证头)
- 加载静态数据集
1.1.4 @AfterEach
在 JUnit 5 中,@AfterEach
注解用于标记一个方法,在每个测试方法执行完之后都会被调用。常用于资源清理、状态重置、关闭连接等。
✅ 基本用法
java
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
class MyServiceTest {
@Test
void testSomething() {
System.out.println("测试逻辑");
}
@AfterEach
void tearDown() {
System.out.println("释放资源");
}
}
🟡 输出示例:
测试逻辑
释放资源
📘 核心特点
特性 | 内容 |
---|---|
来源包 | org.junit.jupiter.api.AfterEach |
执行时机 | 每个 @Test 方法执行 后 调用 |
方法要求 | 无参数、返回 void ,可以抛异常 |
访问级别 | 可为 private 、default 、public |
生命周期支持 | 默认在测试类每次实例化后执行 |
✅ 典型用途
用途 | 示例 |
---|---|
清理临时文件 | Files.deleteIfExists(...) |
关闭网络连接、IO流 | socket.close() |
清除线程上下文或静态变量 | ThreadLocal.remove() |
Mockito 相关清理 | reset(mock) |
🔄 与 @BeforeEach
的配合
java
@BeforeEach
void init() {
System.out.println("初始化资源");
}
@AfterEach
void cleanup() {
System.out.println("销毁资源");
}
@Test
void test1() {
System.out.println("执行测试1");
}
@Test
void test2() {
System.out.println("执行测试2");
}
🟢 输出顺序:
初始化资源
执行测试1
销毁资源
初始化资源
执行测试2
销毁资源
🔍 补充:支持继承和扩展
@AfterEach
可以定义在父类中,子类测试运行时也会自动执行。- 可配合
@TestInstance(Lifecycle.PER_CLASS)
控制是否重用测试类实例。
✅ 示例:资源关闭
java
private Connection conn;
@BeforeEach
void connectToDb() {
conn = DriverManager.getConnection(...);
}
@AfterEach
void closeConnection() throws SQLException {
if (conn != null && !conn.isClosed()) {
conn.close();
}
}
1.1.5 @AfterAll
在 JUnit 5 中,@AfterAll
注解用于标记一个方法,在所有测试方法执行完之后 只调用一次。常用于释放全局资源,例如关闭数据库连接池、终止服务模拟器、清理临时目录等。
✅ 基本用法
java
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
class MyServiceTest {
@Test
void test1() {
System.out.println("执行测试 1");
}
@Test
void test2() {
System.out.println("执行测试 2");
}
@AfterAll
static void tearDownAll() {
System.out.println("所有测试执行后清理资源");
}
}
🟢 输出顺序:
执行测试 1
执行测试 2
所有测试执行后清理资源
📘 特性说明
特性 | 内容 |
---|---|
来源 | org.junit.jupiter.api.AfterAll |
调用频率 | 整个测试类中只调用一次 |
方法签名 | void 返回,无参数,默认必须是 static 方法 |
抛出异常 | 支持 throws Exception |
常见用途 | 释放共享资源(数据库连接池、线程池、TestContainers 等) |
✅ @AfterAll
与 @AfterEach
的区别
注解 | 执行频率 | 是否默认要求 static |
---|---|---|
@AfterEach |
每个测试方法执行后 | 否 |
@AfterAll |
所有测试方法执行后一次 | 是(可通过 @TestInstance 放开) |
✅ 示例:关闭数据库连接池
java
static HikariDataSource dataSource;
@BeforeAll
static void initPool() {
dataSource = new HikariDataSource();
}
@AfterAll
static void closePool() {
if (dataSource != null) {
dataSource.close();
}
}
1.1.6 @ParameterizedTest
@ParameterizedTest
用于参数化测试,可以让同一个测试方法用不同的参数重复执行,避免写重复代码,提高测试覆盖率。
📌 基本用法示例
java
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;
class MyTests {
@ParameterizedTest
@ValueSource(strings = { "racecar", "radar", "level" })
void testPalindrome(String candidate) {
assertTrue(isPalindrome(candidate));
}
boolean isPalindrome(String s) {
return new StringBuilder(s).reverse().toString().equals(s);
}
}
上面代码中,testPalindrome
会针对 "racecar"
, "radar"
, "level"
三个字符串分别执行一次。
🧩 常用参数源(Provider)
注解 | 说明 | 示例 |
---|---|---|
@ValueSource |
直接提供简单类型数组 | @ValueSource(ints = {1,2,3}) |
@EnumSource |
枚举类所有或指定值 | @EnumSource(TimeUnit.class) |
@MethodSource |
通过方法动态生成参数流 | @MethodSource("stringProvider") |
@CsvSource |
多参数,逗号分隔 | @CsvSource({"foo,1", "bar,2"}) |
@CsvFileSource |
从 CSV 文件加载参数 | @CsvFileSource(resources = "/data.csv") |
📝 @MethodSource
示例
java
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
class MyTests {
@ParameterizedTest
@MethodSource("stringProvider")
void testWithMethodSource(String argument) {
assertNotNull(argument);
}
static Stream<String> stringProvider() {
return Stream.of("apple", "banana", "cherry");
}
}
✅ 多参数示例
java
import org.junit.jupiter.params.provider.CsvSource;
class MyTests {
@ParameterizedTest
@CsvSource({
"apple, 1",
"banana, 2",
"cherry, 3"
})
void testWithCsvSource(String fruit, int rank) {
assertNotNull(fruit);
assertTrue(rank > 0);
}
}
⚠️ 注意点
- 参数化测试方法必须至少有一个参数,且参数类型要和提供的参数类型兼容。
- 参数提供方法(
@MethodSource
)必须是static
,返回Stream
、Iterable
、数组等。 - 可以与其他注解(如
@DisplayName
)配合使用。
1.1.7 @MethodSource
@MethodSource
是 @ParameterizedTest
的参数提供方式之一,允许通过静态或实例方法返回参数流(Stream
、Iterable
、数组等),实现更灵活和复杂的参数化测试。
✅ 基本用法
- 注解参数为提供参数的方法名(字符串),该方法返回一个包含测试参数的集合或流。
- 参数方法必须是静态的 (除非测试类使用
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
)。 - 返回类型支持:
Stream<Arguments>
,Stream<T>
,Iterable<T>
,数组。
📋 简单示例
java
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
class MyTests {
@ParameterizedTest
@MethodSource("stringProvider")
void testWithMethodSource(String argument) {
System.out.println("参数: " + argument);
}
static Stream<String> stringProvider() {
return Stream.of("apple", "banana", "cherry");
}
}
执行时,testWithMethodSource
将用 "apple"
、"banana"
、"cherry"
分别执行三次。
📋 多参数示例
如果测试方法有多个参数,可以返回 Stream<Arguments>
,Arguments
是来自 org.junit.jupiter.params.provider.Arguments
。
java
import org.junit.jupiter.params.provider.Arguments;
import java.util.stream.Stream;
class MyTests {
@ParameterizedTest
@MethodSource("stringIntProvider")
void testMultipleParams(String str, int num) {
System.out.println(str + " -> " + num);
}
static Stream<Arguments> stringIntProvider() {
return Stream.of(
Arguments.of("apple", 1),
Arguments.of("banana", 2),
Arguments.of("cherry", 3)
);
}
}
📋 多参数组合:
java
static Stream<Arguments> provideData() {
List<String> list1 = Arrays.asList("apple", "banana", "cherry");
List<String> list2 = Arrays.asList("1","2");
List<String> list3 = Arrays.asList("teset1", "teset2");
return list1.stream().flatMap(content1 ->
list2.stream().flatMap(content2 ->
list3.stream().map(type ->
Arguments.of(content1, content2, type)
)
)
);
}
⚠️ 注意事项
- 参数提供方法名可以省略,如果与测试方法同名,直接写
@MethodSource
即可:
java
@ParameterizedTest
@MethodSource
void testMultipleParams(String str, int num) { ... }
static Stream<Arguments> testMultipleParams() { ... }
- 参数方法可以定义在别的类里,通过
"ClassName#methodName"
指定:
java
@MethodSource("com.example.MyProviders#provideStrings")
- 结合
@TestInstance(Lifecycle.PER_CLASS)
可使用非静态参数方法。
🔄 总结
特性 | 说明 |
---|---|
返回类型 | Stream<T> , Iterable<T> , 数组 |
多参数 | 返回 Stream<Arguments> |
方法修饰 | 默认 static ,非静态需 @TestInstance(PER_CLASS) |
参数方法位置 | 同测试类或其他类(通过全限定名指定) |
1.1.8 @CsvSource
@CsvSource
是 @ParameterizedTest
的一种参数提供方式,支持内联提供逗号分隔的多参数数据,非常适合简单多参数测试。
✅ 基本用法示例
java
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
class MyTests {
@ParameterizedTest
@CsvSource({
"apple, 1",
"banana, 2",
"cherry, 3"
})
void testWithCsvSource(String fruit, int rank) {
assertNotNull(fruit);
assertTrue(rank > 0);
}
}
上面示例中,testWithCsvSource
以三组参数运行三次。
📌 特点和规则
- 参数以逗号分隔,也可以用双引号包裹字符串,支持空格自动去除。
- 支持常用类型:
int
、long
、double
、boolean
、String
、Enum
等。 - 可以通过
null
字符串表示null
,例如:"null, 5"
会将第一个参数传为null
。 - 多个参数对应方法多个参数,顺序匹配。
⚠️ 转义和特殊符号
- 如果参数中有逗号、引号或换行符,需用双引号包裹,内部双引号用
""
转义。
示例:
java
@CsvSource({
"\"apple, green\", 1",
"\"He said \"\"Hello\"\"\", 2"
})
🧩 枚举支持示例
java
enum Color { RED, GREEN, BLUE }
@ParameterizedTest
@CsvSource({
"RED, 1",
"GREEN, 2"
})
void testEnum(Color color, int number) {
assertNotNull(color);
assertTrue(number > 0);
}
🔄 @CsvSource
与 @MethodSource
对比
特性 | @CsvSource |
@MethodSource |
---|---|---|
参数定义 | 静态内联写在注解中 | 通过静态方法返回 |
灵活性 | 适合简单、固定参数 | 适合复杂、动态生成参数 |
多参数支持 | 支持多参数,按顺序匹配 | 支持多参数,使用 Arguments |
参数类型 | 常用类型及枚举 | 可返回任何对象类型 |
📝 典型完整示例
java
@ParameterizedTest
@CsvSource({
"apple, 1, true",
"banana, 2, false",
"'grape, red', 3, true"
})
void testMultipleParams(String fruit, int rank, boolean available) {
assertNotNull(fruit);
assertTrue(rank > 0);
}
1.1.9 JUnit 5 测试生命周期注解执行顺序图
less
┌────────────────────────────┐
│ @BeforeAll (类级别) │ // 只执行一次
└────────────────────────────┘
↓
(对每个测试方法)
┌────────────────────────────┐
│ @BeforeEach │ // 每个测试前执行一次
└────────────────────────────┘
↓
┌────────────────────────────┐
│ @Test / @ParameterizedTest│ // 实际的测试方法
└────────────────────────────┘
↓
┌────────────────────────────┐
│ @AfterEach │ // 每个测试后执行一次
└────────────────────────────┘
↓
┌────────────────────────────┐
│ @AfterAll (类级别) │ // 所有测试完成后执行一次
└────────────────────────────┘
1.1.10 JUnit 5 注解速查表(适合技术笔记)
注解 | 使用范围 | 说明 | 是否支持非 static |
---|---|---|---|
@Test |
方法 | 定义一个测试方法 | ✅ |
@BeforeEach |
方法 | 每个测试前执行 | ✅ |
@AfterEach |
方法 | 每个测试后执行 | ✅ |
@BeforeAll |
方法 | 所有测试开始前执行一次 | ❌(默认),✅(加 @TestInstance(PER_CLASS) ) |
@AfterAll |
方法 | 所有测试结束后执行一次 | ❌(默认),✅(加 @TestInstance(PER_CLASS) ) |
@DisplayName |
类、方法 | 自定义测试显示名称 | ✅ |
@Disabled |
类、方法 | 跳过测试 | ✅ |
@Tag |
类、方法 | 分组测试使用,可通过 mvn -Dgroups 启动 |
✅ |
@Nested |
类 | 支持嵌套测试类 | ✅ |
@TestInstance |
类 | 生命周期控制(默认是 PER_METHOD ) |
✅ |
@ParameterizedTest |
方法 | 参数化测试 | ✅ |
@ExtendWith |
类 | 启用扩展(如 MockitoExtension.class ) |
✅ |
1.2 Mockito 注解
1.2.1 @Mock
@Mock
注解是 Mockito 框架中常用的注解之一,其主要作用是 创建一个模拟对象(mock object),用于单元测试中替代真实对象,以便控制依赖行为、隔离测试逻辑。
🔍 使用场景
当你在测试类中需要依赖某个类的对象,而这个类的行为复杂、依赖外部资源(如数据库、网络)、或你只关心它的方法返回值时,就可以使用 @Mock
。
✅ 使用方法
java
@RunWith(MockitoJUnitRunner.class) // 或使用 @ExtendWith(MockitoExtension.class)(Junit5)
public class MyServiceTest {
@Mock
private MyRepository myRepository;
@InjectMocks
private MyService myService;
@Test
public void testDoSomething() {
when(myRepository.getData()).thenReturn("mock data");
String result = myService.doSomething();
assertEquals("expected", result);
}
}
🧠 作用详解
@Mock
:用于创建一个 虚拟对象(Mock对象) ,这个对象的行为可以预设(when...thenReturn
)。@InjectMocks
:自动将@Mock
创建的模拟对象注入到被测试的类中。- 模拟对象不会执行真实逻辑,而是返回你指定的值或行为。
📌 注意事项
-
使用
@Mock
时必须初始化 mock 对象,常见方式有:- 使用
MockitoAnnotations.initMocks(this)
(Junit4); - 使用
@RunWith(MockitoJUnitRunner.class)
; - 使用
@ExtendWith(MockitoExtension.class)
(Junit5)。
- 使用
-
@Mock
并不会自动注入到测试对象中,除非使用@InjectMocks
或手动注入。
1.2.2 @InjectMocks
📌 作用
@InjectMocks
是 Mockito 提供的注解,用于创建待测试类的实例并自动注入其依赖项(被 @Mock/@Spy 标注的字段)。它是 Mockito 自动化依赖注入的关键手段之一。
✅ 使用示例
java
@ExtendWith(MockitoExtension.class)
class MyServiceTest {
@Mock
private MyRepository repository;
@InjectMocks
private MyService service;
@Test
void testDoSomething() {
when(repository.getData()).thenReturn("mocked");
String result = service.doSomething();
assertEquals("processed mocked", result);
}
}
在上面例子中:
@InjectMocks
会创建MyService
实例。- 将上面定义的
@Mock MyRepository
注入到MyService
的构造方法、字段或setter
中。
🧠 注入顺序(优先级)
Mockito 会按以下顺序查找依赖注入点:
- 构造函数注入(如果只有一个构造函数)
@Autowired
/@Inject
标注的构造函数(如果多个构造函数)- 字段注入
- Setter 方法注入
⚙️ 自动注入原理
Mockito 会尝试匹配字段类型并注入可用的 @Mock
实例。例如:
java
class MyService {
private final MyRepository repository;
public MyService(MyRepository repository) {
this.repository = repository;
}
}
上述情况中,Mockito 会将 @Mock MyRepository
传入构造函数中。
⚠️ 注意事项
- 如果字段/构造函数中没有对应的
@Mock
或@Spy
实例,Mockito 会尝试用null
填充。 - 如果你使用
final
类/字段,需要启用 Mockito inline 模式(你已经使用了)。 - 字段必须是非
private
或提供 setter 方法,否则你不能通过字段注入。
1.2.3 @Spy
📌 作用
@Spy
是 Mockito 提供的注解,用于创建一个真实对象的"部分模拟对象" ,保留其真实行为的同时,可以通过 when()
或 doReturn()
控制部分方法的返回值。
适用于:
- 想使用真实对象的大部分行为
- 只替换部分行为进行 mock
✅ 基本示例
java
@ExtendWith(MockitoExtension.class)
class MyServiceTest {
@Spy
private ArrayList<String> list = new ArrayList<>();
@Test
void testWithSpy() {
list.add("real");
when(list.size()).thenReturn(100);
assertEquals("real", list.get(0)); // 真实行为
assertEquals(100, list.size()); // 被 mock 的方法
}
}
💡 特点与行为
特性 | 说明 |
---|---|
创建真实对象实例 | 与 @Mock 不同,@Spy 是包装真实对象 |
支持真实方法调用 | 除非特别用 when() /doReturn() 指定 |
支持依赖注入 | 可被 @InjectMocks 注入到目标类中 |
可用于 final/私有类 | 需启用 mockito-inline |
需要避免 null Pointer | 未初始化时直接调用真实方法会抛异常 |
⚠️ 使用注意
1. 推荐用 doReturn().when()
代替 when().thenReturn()
避免真实方法在 stub 时被调用(尤其当方法有副作用):
java
// ✅ 推荐用法(不会执行真实方法)
doReturn(100).when(list).size();
// ❌ 不推荐(size() 会先被执行一次)
when(list.size()).thenReturn(100);
2. 初始化方式:
- 如果是普通类如
ArrayList
,推荐直接赋值:
java
@Spy
private List<String> list = new ArrayList<>();
- 如果是非默认构造函数,使用
@Spy
+@InjectMocks
自动注入:
java
class MyService {
private final MyDependency dep;
MyService(MyDependency dep) { this.dep = dep; }
}
@Spy
MyDependency realDep = new MyDependency("init");
@InjectMocks
MyService service;
📌 @Spy与 @Mock 区别对比
特性 | @Mock |
@Spy |
---|---|---|
调用真实方法 | ❌ 否,默认所有方法返回默认值 | ✅ 是,除非被 stub 掉 |
适合场景 | 完全隔离依赖,测试业务逻辑 | 局部替换逻辑,验证真实交互 |
初始化对象 | 由 Mockito 创建 | 需你初始化或通过构造注入 |
2.模拟
在使用 Mockito(含 inline mockito) 进行单元测试时,静态方法(static) 和 构造函数(constructor) 的模拟属于高级用法,默认的 Mockito 是不支持这类模拟的。你使用的 inline-mockito(mockito-inline) 是专门为支持这些功能而设计的。
🧭 一、前提:启用 inline mockito
你必须引入以下依赖(以 Maven 为例):
xml
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>5.x.x</version> <!-- 5+ 推荐 -->
<scope>test</scope>
</dependency>
⚙️ 二、静态方法模拟(Static Mocking)
✅ 使用方式(JDK 8 + mockito-inline)
java
try (MockedStatic<Utils> mockedStatic = Mockito.mockStatic(Utils.class)) {
mockedStatic.when(() -> Utils.staticMethod()).thenReturn("mocked result");
String result = MyService.callStatic();
assertEquals("mocked result", result);
}
📌 说明
-
Mockito.mockStatic(Class<T> clazz)
会启用对静态类的 mock,返回MockedStatic<T>
。 -
使用完后自动释放(推荐用 try-with-resources)。
-
可 mock 多个方法,也可以
verify
调用:javamockedStatic.verify(() -> Utils.staticMethod());
🧱 三、构造函数模拟(Constructor Mocking)
Mockito 也支持拦截构造器调用,返回你预设的 mock 实例。
✅ 使用方式(Mockito 5 + inline)
java
try (MockedConstruction<HeavyService> mocked = Mockito.mockConstruction(HeavyService.class,
(mock, context) -> {
when(mock.loadData()).thenReturn("mocked data");
})) {
MyService service = new MyService(); // 内部会 new HeavyService()
String result = service.callHeavy();
assertEquals("mocked data", result);
}
📌 说明
-
Mockito.mockConstruction(Class<T> class)
会拦截new
操作。 -
可使用 lambda 设置行为
(mock, context) -> { ... }
-
支持获取多次构造的实例列表:
javaList<HeavyService> allInstances = mocked.constructed();
📎 注意事项(常见坑)
项目 | 说明 |
---|---|
inline-mockito | 必须启用,mockito-core 不支持这些功能 |
JDK | 要求至少 JDK 8(推荐 JDK 11+) |
不可与 PowerMock 混用 | mockito-inline 已可替代 PowerMock 大部分功能 |
静态/构造模拟需最小化使用 | 违反了面向对象原则,建议在无法重构时使用 |
🎯 示例场景
场景 | 用法 |
---|---|
LocalDate.now() 模拟当前时间 |
Mockito.mockStatic(LocalDate.class) |
UUID.randomUUID() 控制随机值 |
同上 |
模拟内部 new 出来的服务类 | mockConstruction 替代实际调用,控制副作用 |