You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JUnit 5中为测试隔离初始化Spring Bean?

如何在JUnit 5 + Spring测试中实现每个测试方法重新初始化Spring Bean

在JUnit 5和Spring测试场景中,我们希望每个测试用例都能使用全新的Spring Bean实例,避免不同测试间的状态污染。

JUnit 5默认会在每个测试方法执行前创建新的测试类实例,因此普通实例变量能自动实现隔离,比如下面的代码可以正常运行:

public class TestInstanceVaribale{
    
    int number = 0;

    @Test
    public void test1() {
        number += 3;
        Assertions.assertEquals(3, number);
    }
    
    @Test
    public void test2() {
        number += 5;
        Assertions.assertEquals(5, number);
    }
}

但Spring Bean默认是单例模式,容器会复用同一个实例,导致测试间互相影响。比如下面的代码执行会失败:

Car类

@Component
public class Car {
    public String name = "myCar";
}

测试类

import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;

@SpringBootTest
@TestMethodOrder(OrderAnnotation.class)
public class TestSpringVariable {

    @Autowired
    Car car;
    
    @Test
    @Order(1)
    public void test1() {
        car.name = "testCar";
        Assertions.assertEquals("testCar", car.name);
    }
    
    @Test
    @Order(2)
    public void test2() {
        // 执行失败:预期值是myCar,实际值是testCar
        Assertions.assertEquals("myCar", car.name); 
    }
}

我们期望实现类似这样的效果:每个测试方法都重新初始化Spring Bean:

@SpringBootTest
// 期望有类似@InitializeSpringBeanPerMethod的注解
public class TestSpringVariable2 {

    @Autowired
    Car car;
    
    @BeforeEach
    public void initialize() { 
        // 期望有类似SpringBean.initialize()的方法重置Bean
    }
}

解决方案

方法一:使用@DirtiesContext刷新整个Spring上下文

通过@DirtiesContext标记测试方法执行后刷新上下文,确保每个测试方法都使用全新的容器和Bean实例:

import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.MethodMode;

@SpringBootTest
@TestMethodOrder(OrderAnnotation.class)
public class TestSpringVariable {

    @Autowired
    Car car;
    
    @Test
    @Order(1)
    @DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
    public void test1() {
        car.name = "testCar";
        Assertions.assertEquals("testCar", car.name);
    }
    
    @Test
    @Order(2)
    @DirtiesContext(methodMode = MethodMode.AFTER_METHOD)
    public void test2() {
        Assertions.assertEquals("myCar", car.name); 
    }
}
  • methodMode = MethodMode.AFTER_METHOD表示每个测试方法执行完成后,Spring上下文会被标记为"脏"并重新创建,下一个测试方法会使用全新的上下文和Bean。

方法二:将Bean改为prototype作用域,配合@BeforeEach重新获取

如果只需要特定Bean实现隔离,无需刷新整个上下文,可以将Bean的作用域改为prototype,并在每个测试前重新获取实例:

修改Car类

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class Car {
    public String name = "myCar";
}

测试类

import org.springframework.context.ApplicationContext;

@SpringBootTest
@TestMethodOrder(OrderAnnotation.class)
public class TestSpringVariable2 {

    @Autowired
    ApplicationContext context;
    
    private Car car;
    
    @BeforeEach
    public void init() {
        // 每次测试前从容器获取新的Car实例
        car = context.getBean(Car.class);
    }
    
    @Test
    @Order(1)
    public void test1() {
        car.name = "testCar";
        Assertions.assertEquals("testCar", car.name);
    }
    
    @Test
    @Order(2)
    public void test2() {
        Assertions.assertEquals("myCar", car.name); 
    }
}
  • prototype作用域的Bean每次从容器获取时都会创建新实例,因此@BeforeEach中重新获取就能保证每个测试用例拿到的是全新的Bean。

内容的提问来源于stack exchange,提问作者bittap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 22:45:37