【问题标题】:How to override/replace @MockBean field declared in the parent class with @Autowired real bean如何用@Autowired real bean覆盖/替换父类中声明的@MockBean字段
【发布时间】:2021-05-01 16:13:36
【问题描述】:

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

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

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

public AnotherTest extends BaseTest {
    @Autowired
    protected OneService oneService;

即使我使用了@Autowired 注释,oneService 字段也将是从BaseTest 继承的模拟实例。

有没有办法强制注入使用自动连线?

【问题讨论】:

  • 基于对 Spring Boot Test 内部结构的快速浏览,我认为目前不可能实现这一目标。 DefinitionsParser 似乎没有考虑到字段可能被子类覆盖:github.com/spring-projects/spring-boot/blob/master/…
  • 尝试构造函数注入,这种方式可能可以将 bean 从子级提供给父级,看看这种方法,可能会有所帮助。
  • 谢谢。有没有我想做的选择?我正在考虑使用@ Qualifier,但这意味着我需要分别将 bean 初始化为带有限定符的模拟和实际 OneService。我正在努力让它发挥作用。我可能会在某个地方错过理解。 @MockBean 自动注入到上下文中,所以我无能为力,所以我只能用限定符更新 OneService 实现并更改所有使用它的地方?

标签: java spring-boot mockito integration-testing spring-test


【解决方案1】:

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

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

因此,解决方案是通过在超类中通过@Autowired 注入真正的 bean,然后为子类中的特定 bean 类型打开模拟来反转您正在尝试做的事情。

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

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

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

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

}

【讨论】:

  • 感谢 Sam 的精彩解释。这真的很有帮助
猜你喜欢
  • 2011-10-17
  • 1970-01-01
  • 2013-10-02
  • 1970-01-01
  • 1970-01-01
  • 2015-06-30
  • 2016-10-11
  • 2013-06-03
  • 1970-01-01
相关资源
最近更新 更多