【问题标题】:@MockBean injected into a constructor-autowired component@MockBean 注入到构造函数自动装配的组件中
【发布时间】:2022-10-24 01:58:35
【问题描述】:

来自official documentation

按类型注册时,上下文中任何现有的匹配类型(包括子类)的单个 bean 都将被 mock 替换

但是,如果被测服务在构造函数中自动装配怎么办?例如。在 Kotlin 中(我想 @MockkBean@MockBean 对于 DI 的工作方式相同):

 @RunWith(SpringRunner.class)
 class ExampleTests @Autowired constructor(val userOfService: UserOfService) {

   @MockkBean
   private lateinit var service: ExampleService

   ...
}

我希望这个例子会失败,因为为了实例化ExampleTests,Spring 必须首先获得一个正确的UserOfService 实例。不过,这在当时是不可能的,因为在应用程序上下文中还没有 ExampleService 类型的 bean。

出乎我的意料,这行得通。这怎么可能?

【问题讨论】:

    标签: spring dependency-injection mockito spring-boot-test mockk


    【解决方案1】:

    因为您错过了文档中的另一部分:

    在任何一种情况下,如果没有定义现有的 bean,则将是一个新的 添加。

    因此,@MockBean 也会自动实例化一个 bean,如果在 spring 上下文中找不到该 bean。

    动作顺序主要如下:

    1. 启动 spring 上下文,它只创建所有在 spring 上下文中注册的 spring BeanDefinition

    2. 处理 @MockBean 将替换 (1) 中的 BeanDefinition 或创建一个新的 BeanDefinition

    3. 实际上基于这些BeanDefinition 实例化所有bean。它将先处理实际实例化的 bean,然后再处理。

    4. 创建一个测试实例(即 ExampleTests)来执行它的测试方法。如果没有创建任何需要自动连接到测试实例的 bean,它将失败。

      因此,只要您定义 UserOfService bean ,就可以实例化 ExampleTests ,就像您现在在 ExampleService 上使用 @MockBean 一样,这意味着无论您是否在测试的 spring 上下文中定义它,它都必须存在。

    【讨论】:

    • 是的,我读过那部分。问题可能更多的是关于时间的,即@MockkBean 声明的处理时间,即它何时注册到应用程序上下文?我会说作为ExampleTests 实例化的一部分,但只有构造函数参数实例化。如果这是真的,那么UserOfService 不能被实例化,因为ExampleService 还没有被实例化。这个论点有什么问题?
    • @大卫库贝克。这是因为@MockkBean 将在实例化ExampleTests 之前被处理。我已经更新了我的答案。请检查
    • 我不明白 Spring 如何在没有仅在步骤 2 中创建的必需依赖项 ExampleService 的情况下完成步骤 1(实例化所有 bean)。
    • 我一定遗漏了一些关于 Spring DI 机制内部工作的“明显”信息:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-19
    • 1970-01-01
    • 1970-01-01
    • 2022-11-29
    • 1970-01-01
    • 2017-01-07
    相关资源
    最近更新 更多