如何 override/replace 在父 class 中声明的@MockBean 字段与 @Autowired 真实 bean

How to override/replace @MockBean field declared in the parent class with @Autowired real bean

为了避免 Spring 上下文一次又一次地重新加载,我已将 @MockBean 带注释的注入移动到父级 class,类似这样。

@SpringBootTest
.......
public abstract  BaseTest {
    @MockBean
    protected OneService oneService;

这用于测试 classes,它需要 OneService 的模拟。但是,对于我也想从 BaseTest 扩展的测试,但是通过 @Autowired 注入真正的 OneService 将不起作用,因为它将继承 BaseTest 的模拟注入].

public AnotherTest extends BaseTest {
    @Autowired
    protected OneService oneService;

即使我使用了 @Autowired 注释,oneService 字段将是从 BaseTest.

继承的模拟实例

有没有办法强制注入使用自动装配?

在 Java 中,技术上无法覆盖字段。当您在 subclass 中声明具有相同名称的字段时,该字段会隐藏 superclass 中具有相同名称的字段。所以这是一个障碍。

第二个障碍源于这样一个事实,即如果 superclass 配置,Spring Boot 的测试支持无法关闭 subclass 中的 bean 模拟通过 @MockBean.

的嘲笑

因此,解决方案是通过在 superclass 中通过 @Autowired 注入真正的 bean,然后在子class.

  1. 在 superclass 中声明 @Autowired 字段,但不要在 subclass 中重新声明该字段。
  2. 在子class级别声明@MockBeanclass,指定要模拟的classes(即bean类型)。

最后一步导致继承字段在子class中注入模拟。

以下两个 class 在实践中演示了此技术。

@SpringBootTest(classes = BaseTests.Config.class)
class BaseTests {

    @Autowired
    protected Service service;

    @Test
    void service() {
        assertThat(service.getMessage()).isEqualTo("real");
    }

    @Configuration
    static class Config {

        @Bean
        Service service() {
            return new Service();
        }
    }

    static class Service {
        String getMessage() {
            return "real";
        }
    }

}
@MockBean(classes = BaseTests.Service.class)
class MockBeanTests extends BaseTests {

    @BeforeEach
    void setUpMock() {
        when(service.getMessage()).thenReturn("mock");
    }

    @Test
    @Override
    void service() {
        assertThat(service.getMessage()).isEqualTo("mock");
    }

}