Junit5测试类编写笔记

技术栈: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(不能有返回值)
方法签名 可以是 privatedefaultpublic,推荐使用 defaultpublic
方法参数 默认不接受参数(除非使用扩展机制)
抛出异常 方法可以抛出异常,如 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
方法修饰符 可以是 publicprotectedpackage-private(不强制是 public
方法签名 必须是无参、返回 void 的实例方法
执行顺序 每个 @Test 执行前都调用一次
可继承性 如果在父类中定义 @BeforeEach,子类也会调用(类似模板方法)

✅ 常见用途
  1. 初始化被测试对象
  2. 重置 mock 对象
  3. 构建测试数据
  4. 日志打印或资源准备

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,可以抛异常
访问级别 可为 privatedefaultpublic
生命周期支持 默认在测试类每次实例化后执行

✅ 典型用途
用途 示例
清理临时文件 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,返回 StreamIterable、数组等。
  • 可以与其他注解(如 @DisplayName)配合使用。

1.1.7 @MethodSource

@MethodSource@ParameterizedTest 的参数提供方式之一,允许通过静态或实例方法返回参数流(StreamIterable、数组等),实现更灵活和复杂的参数化测试。

✅ 基本用法
  • 注解参数为提供参数的方法名(字符串),该方法返回一个包含测试参数的集合或流。
  • 参数方法必须是静态的 (除非测试类使用 @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 以三组参数运行三次。


📌 特点和规则
  • 参数以逗号分隔,也可以用双引号包裹字符串,支持空格自动去除。
  • 支持常用类型:intlongdoublebooleanStringEnum 等。
  • 可以通过 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 会按以下顺序查找依赖注入点:

  1. 构造函数注入(如果只有一个构造函数)
  2. @Autowired/@Inject 标注的构造函数(如果多个构造函数)
  3. 字段注入
  4. 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 调用:

    java 复制代码
    mockedStatic.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) -> { ... }

  • 支持获取多次构造的实例列表:

    java 复制代码
    List<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 替代实际调用,控制副作用

相关推荐
黄暄3 天前
分布式锁优化:使用Lua脚本保证释放锁的原子性问题
java·redis·分布式·后端·junit·lua
cxh_陈5 天前
org.junit.runners.model.InvalidTestClassError:此类问题的解决
java·开发语言·junit
.生产的驴8 天前
SpringBoot 执行Lua脚本 服务端执行 减少性能损耗 优化性能 优化连接性能
java·数据库·spring boot·后端·junit·maven·lua
小小数媒成员9 天前
Unity—lua基础语法
unity·junit·lua
奋斗的老史9 天前
利用Lua脚本限制用户的访问频率
开发语言·junit·lua
渡梦酒10 天前
Redis批量删除Key的三种方式
数据库·redis·junit
兰德里的折磨55010 天前
为什么要使用stream流
java·jvm·spring boot·spring·junit·log4j·intellij-idea
i1yo_kiki11 天前
junit单元测试
junit·log4j
啥都想学的又啥都不会的研究生11 天前
log日志最佳实践
java·spring boot·后端·spring·junit·log4j·logback