如何使用@Autowired real bean 覆盖/替换父类中声明的@MockBean 字段

问题描述

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

@SpringBoottest
.......
public abstract  BaseTest {
    @MockBean
    protected Oneservice oneservice;

这为需要模拟 Oneservice 的测试类提供服务。但是,对于我也想从 BaseTest 扩展的测试,但是通过 Oneservice 注入真正的 @Autowired 将不起作用,因为它将继承 {{1} }.

BaseTest

即使我使用了 public AnotherTest extends BaseTest { @Autowired protected Oneservice oneservice; 注释,@Autowired 字段也将是从 oneservice 继承的模拟实例。

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

解决方法

在 Java 中,技术上无法覆盖字段。当您在子类中声明同名字段时,该字段会隐藏超类中的同名字段。所以这是一个障碍。

第二个障碍源于这样一个事实:如果超类通过 DateTimeFormatter fmt = DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss").withZone(DateTimeZone.forID( "Europe/Berlin")); DateTime dt = fmt.parseDateTime(lastModifid); dt.toString() 配置模拟,则 Spring Boot 的测试支持无法关闭子类中 bean 的模拟。

因此,解决方案是通过在超类中通过 @MockBean 注入真正的 bean,然后在子类中打开对特定 bean 类型的模拟来反转您正在尝试执行的操作。

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

最后一步导致继承的字段被注入子类中的模拟。

以下两个课程在实践中演示了这种技术。

@MockBean
@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";
        }
    }

}