常用ExtendWith介绍

一、常用扩展概览

JUnit 5 提供了丰富的扩展机制,以下是一些常用的扩展及其作用:

扩展名称核心功能
MockitoExtension集成 Mockito 框架,支持依赖注入和 Mock 对象管理。
SpringExtension集成 Spring 框架,支持 Spring 上下文加载和依赖注入。
TempDirectory自动创建和清理临时目录。
ConditionalExecution根据条件动态跳过或执行测试。
TimingExtension记录测试执行时间。
ParameterResolver自定义参数解析(依赖注入)。
TestWatcher监控测试执行状态(如成功、失败、跳过)。

二、常用扩展详细介绍

1. MockitoExtension

功能:集成 Mockito 框架,支持依赖注入和 Mock 对象管理。
使用场景:单元测试中需要 Mock 依赖对象时。

示例

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void testFindUserById() {
        when(userRepository.findById(1L)).thenReturn(new User(1L, "Alice"));
        User user = userService.findUserById(1L);
        Assertions.assertEquals("Alice", user.getName());
    }
}

2. SpringExtension

功能:集成 Spring 框架,支持 Spring 上下文加载和依赖注入。
使用场景:Spring 应用的集成测试。

示例

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {TestConfig.class})
class UserServiceSpringTest {

    @Autowired
    private UserService userService;

    @Test
    void testFindUserById() {
        User user = userService.findUserById(1L);
        Assertions.assertEquals("Alice", user.getName());
    }
}

3. TempDirectory

功能:自动创建和清理临时目录。
使用场景:测试中需要临时文件或目录时。

示例

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.api.extension.ExtendWith;
import java.nio.file.Path;

@ExtendWith(TempDirectory.class)
class TempDirTest {

    @Test
    void testTempDir(@TempDir Path tempDir) {
        Path file = tempDir.resolve("test.txt");
        Assertions.assertFalse(Files.exists(file));
    }
}

4. ConditionalExecution

功能:根据条件动态跳过或执行测试。
使用场景:根据环境变量、配置或运行时条件决定是否执行测试。

示例

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;

@ExtendWith(ConditionalExecution.class)
class ConditionalTest {

    @Test
    @EnabledIfEnvironmentVariable(named = "ENV", matches = "CI")
    void testOnlyInCI() {
        Assertions.assertTrue(true);
    }
}

5. TimingExtension

功能:记录测试执行时间。
使用场景:性能测试或监控测试耗时。

示例

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(TimingExtension.class)
class TimingTest {

    @Test
    void fastTest() throws InterruptedException {
        Thread.sleep(100);
    }

    @Test
    void slowTest() throws InterruptedException {
        Thread.sleep(200);
    }
}

6. ParameterResolver

功能:自定义参数解析(依赖注入)。
使用场景:测试方法需要动态注入参数时。

示例

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolver;

@ExtendWith(CustomParameterResolver.class)
class ParameterResolverTest {

    @Test
    void testWithCustomParameter(String input) {
        Assertions.assertEquals("Hello", input);
    }
}

class CustomParameterResolver implements ParameterResolver {

    @Override
    public boolean supportsParameter(ParameterContext paramCtx, ExtensionContext extCtx) {
        return paramCtx.getParameter().getType() == String.class;
    }

    @Override
    public Object resolveParameter(ParameterContext paramCtx, ExtensionContext extCtx) {
        return "Hello";
    }
}

7. TestWatcher

功能:监控测试执行状态(如成功、失败、跳过)。
使用场景:记录测试结果或执行额外逻辑(如发送通知)。

示例

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.TestWatcher;
import org.junit.jupiter.api.extension.ExtensionContext;

@ExtendWith(CustomTestWatcher.class)
class TestWatcherTest {

    @Test
    void successfulTest() {
        Assertions.assertTrue(true);
    }

    @Test
    void failedTest() {
        Assertions.fail("故意失败");
    }
}

class CustomTestWatcher implements TestWatcher {

    @Override
    public void testSuccessful(ExtensionContext context) {
        System.out.println("测试成功: " + context.getDisplayName());
    }

    @Override
    public void testFailed(ExtensionContext context, Throwable cause) {
        System.out.println("测试失败: " + context.getDisplayName());
    }
}

三、组合使用扩展

多个扩展可以通过 @ExtendWith 组合使用:

@ExtendWith({MockitoExtension.class, TimingExtension.class})
class CombinedTest {
    // ...
}

四、总结

常用扩展的作用

  • MockitoExtension:简化 Mock 对象管理。
  • SpringExtension:集成 Spring 上下文。
  • TempDirectory:管理临时文件。
  • ConditionalExecution:动态控制测试执行。
  • TimingExtension:监控测试耗时。
  • ParameterResolver:自定义依赖注入。
  • TestWatcher:监控测试状态。

推荐实践

  • 优先使用成熟的第三方扩展(如 Mockito、Spring 的扩展)。
  • 在需要复用逻辑时开发自定义扩展。
  • 通过组合扩展实现复杂测试需求。
### 集成单元测试 在 Spring Boot 中,`spring-boot-starter-test` 是一个非常重要的模块,它集成了多个用于编写和运行测试的库,包括 JUnit、Mockito 和 AssertJ 等[^1]。为了更好地支持JUnit 5平台上的扩展模型,Spring Framework引入了 `@ExtendWith` 注解。 #### @ExtendWith 注解的作用 `@ExtendWith` 注解允许开发者指定自定义的扩展来增强测试功能。这些扩展可以提供额外的功能,比如管理资源生命周期、注入依赖项或是修改执行上下文等。此注解通常应用于类级别或方法级别上,在JUnit Jupiter中用来替代旧版本中的各种规则(Rules)和运行器(Runners)。对于与Spring框架集成而言,最常见的是配合使用由org.springframework.test.context.junit.jupiter包提供的特定实现——例如`SpringExtension`,从而使得能够利用完整的应用上下文来进行更复杂的场景模拟[^4]。 ```java import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.test.web.servlet.MockMvc; @WebMvcTest(controllers = MyController.class) class MyControllerTests { @Autowired private MockMvc mockMvc; @Test void shouldReturnDefaultMessage() throws Exception { this.mockMvc.perform(get("/hello")) .andExpect(status().isOk()) .andExpect(content().string("Hello, World!")); } } ``` 上述代码片段展示了如何通过 `@WebMvcTest` 来限定只加载必要的组件以便快速高效地完成控制器层面上的切片测试;而这里并没有显式地看到 `@ExtendWith(SpringExtension.class)` ,因为当我们在测试类上面标注了诸如 `@SpringBootTest`, `@DataJpaTest`, 或者像这里的 `@WebMvcTest` 这样的组合注解时,默认情况下已经隐含包含了这个配置[^2]。 #### 日志输出设置 如果希望调整日志等级以减少不必要的干扰信息,则可以在项目的resources目录下创建logback-test.xml文件,并按照如下方式设定: ```xml <configuration> <logger name="com.example.myapp" level="INFO"/> </configuration> ``` 这会确保来自应用程序的日志仅显示 info 及以上级别的消息到控制台上[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值