谨慎使用 @MockBean注解

本文指出在Spring Boot单元测试中,使用@MockBean或@SpyBean会改变bean在context中的状态,导致spring test context刷新,引发多个tests重复启动context等问题。针对非web工程和web工程分别给出快速解决方案,同时提及可能潜在的问题,并提供相关阅读和资料。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题定位

@MockBean或@SpyBean会改变bean在context中的状态,为了保证每个test运行时context不被污染而进行刷新,属于正常现象,是springboot的默认行为。但由此会导致其他不可预料的错误。

springboot提供了spirng-boot-starter-test以供开发者使用单元测试,其中org.springframework.boot.test的mockito包,是springboot对org.mockito的增强替换,@MockBean和@SpyBean是主要的mock注解。

tests使用@MockBean和@SpyBean会导致bean在spring test context中缓存的cache key变化,springboot默认缓存context,当顺序执行的两个tests分别依赖不同的但需要被mock的bean或者同一个bean而在其中一个test中需要被mock时(或者其他会污染context的行为),spring test context发生变化,进而引起运行第二个test前刷新context。

于是多个tests重复启动spring test context(较早的context不会自动关闭?jvm中已存在class meta?),不能保证每个tests的执行上下文的独立性、隔离性,某一些bean在被多次创建后会出现异常。

参考issue

Spring boot test: context loaded for every test?
Context not being reused in tests when MockBeans are used
Context isn’t cached when MockBean using
@SpyBean makes context restart between two tests

文档释义

Mocking and Spying Beans
在这里插入图片描述
Context Management and Caching
在这里插入图片描述

解决方案

快速方案

一、对于非web工程
将用例中使用的mock变量放到父类,这样所有的用例类都使用同一个上下文,具体的mock放到实际的测试用例类上。

//测试父类
@RunWith(SpringJUnit4ClassRunner.class)
public class XxxTestBase {
    @MockBean
    private BeanService1 beanService1;

    @MockBean
    private BeanService2 beanService2;

    @MockBean
    private BeanService2 beanService2;
}

//具体的测试类
public class ConcreteTest extends XxxTestBase {
 
    @Test
    public void test() {
		beanService2.doTest();
    }
        
}

二、对于web工程
如果是web工程,spring context刷新会导致端口冲突,通过设置端口随机来避免。

@springbootTest(class=SOFABootTestApplication.class, WebEnironment=WebEnvironment.RANDOM_PORT)

参考文档:Testing Spring Boot Applications

可能潜在的问题
1.把该bean不需要被mock的方法一起mock了(@SpyBean替换@MockBean?);
2.一些场景下该bean不需要被mock,而上下文中该bean是被mock的;
3.web工程设置为端口随机,可能会导致某些依赖端口的用例出现失败;

相关阅读

Do You Really Need @DirtiesContext?

Annotation Type DirtiesContext

其他资料

Mockito.mock() vs @Mock vs @MockBean
Think Twice Before Using @MockBean

### 如何在 IntelliJ IDEA 中使用 PowerMock 进行单元测试 #### 配置 PowerMock 的依赖项 为了在 IntelliJ IDEA 中使用 PowerMock,首先需要引入必要的 Maven 或 Gradle 依赖项。以下是基于 `Gradle` 和 `Maven` 的两种方式。 对于 **Gradle** 用户,可以在项目的 `build.gradle.kts` 文件中添加以下内容[^3]: ```kotlin dependencies { testImplementation("org.powermock:powermock-module-junit4:2.0.9") testImplementation("org.powermock:powermock-api-mockito2:2.0.9") } ``` 如果使用的是 **Maven** 构建工具,则可以将以下片段加入到 `pom.xml` 文件中: ```xml <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>2.0.9</version> <scope>test</scope> </dependency> ``` 完成上述操作后,执行刷新构建文件的操作以下载并应用这些依赖项。 --- #### 创建一个简单的 Java 类用于演示 假设有一个类名为 `StaticClass`,其中包含了一个静态方法 `staticMethod()`,我们希望对其进行测试。 ```java public class StaticClass { public static String staticMethod() { return "Original Value"; } } ``` --- #### 编写 PowerMock 测试案例 下面是一个完整的 JUnit 4 测试用例示例,展示如何通过 PowerMock 来模拟静态方法的行为。 ```java import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.junit.Assert.assertEquals; @RunWith(PowerMockRunner.class) @PrepareForTest(StaticClass.class) // 准备要被模拟的类 public class StaticClassTest { @Test public void testStaticMethod() throws Exception { // 模拟静态方法返回自定义值 PowerMockito.mockStatic(StaticClass.class); Mockito.when(StaticClass.staticMethod()).thenReturn("Mocked Value"); // 调用实际的方法 String result = StaticClass.staticMethod(); // 断言结果是否符合预期 assertEquals("Mocked Value", result); // 验证静态方法确实被调用了 PowerMockito.verifyStatic(StaticClass.class, Mockito.times(1)); StaticClass.staticMethod(); } } ``` 在此代码中: - 使用了 `@RunWith(PowerMockRunner.class)` 注解来指定运行器。 - 利用 `@PrepareForTest` 注明哪些类会被修改其行为。 - 方法内部通过 `PowerMockito.mockStatic` 对目标静态方法进行了替换,并设置了期望的结果。 --- #### 在 IntelliJ IDEA 中启用注解处理器支持 由于某些情况下可能涉及字节码增强技术,因此需确认 IDE 已开启注解处理器功能: 1. 打开菜单栏中的 **File -> Settings**; 2. 导航至 **Build, Execution, Deployment -> Compiler -> Annotation Processors**; 3. 勾选选项框 “Enable annotation processing”。 此步骤有助于确保编译期间能够正确处理由 PowerMock 提供的功能扩展。 --- #### 注意事项 尽管 PowerMock 功能强大,但在现代开发实践中应谨慎选用它。因为过度依赖此类库可能会掩盖设计上的缺陷或者增加维护成本。例如,在 Spring Boot 应用程序里更推荐采用官方提供的解决方案如 [@MockBean][^1] 替代直接操控底层细节的方式。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值