【问题标题】:How to use @MockBean without having to @Inject the Bean again?如何使用@MockBean 而不必再次@Inject Bean?
【发布时间】:2021-04-20 18:43:57
【问题描述】:

有没有更简洁/优雅的方式在 Micronaut 中实现此功能?

@MicronautTest
class ControllerTest {
    @Inject
    @field:Client("/")
    lateinit var client: RxHttpClient

    @Inject
    lateinit var redeemService: RedeemService

    @MockBean(RedeemService::class)
    fun redeemService(): RedeemService = mockk {
        every { validate(any()) } returns true
    }

    @Test
    fun test() {
        // some logic triggering a call to redeemService
        verify(exactly = 1) {
            redeemService.validate("123")
        }
    }
}

对我来说,必须声明 @MockBean 然后还必须声明 @Inject 之前声明的 @MockBean 似乎是多余的工作。 据我所知,在 Spring Boot 中,这只是 lateinit var 上的注释。

我是否误解或忽略了什么?

【问题讨论】:

  • “对我来说,必须声明 MockBean 然后还必须注入先前声明的 MockBean 看起来像是多余的工作” - 通常模拟不会注入到测试中,而是注入到组件中正在测试。在您的情况下,您的测试除了模拟本身之外不测试任何东西,因此不清楚您真正想要完成什么。
  • 我猜 Mock 可以服务于 2 个目的:将单元的行为与系统的其余部分隔离开来 + 捕获跨越此边界的信息(以及频率等)。对我来说,经常使用这两个功能是完全正常的,这就是为什么我也在 Micronaut 中寻找类似于 github.com/Ninja-Squad/springmockk 的东西。

标签: unit-testing junit micronaut mockk


【解决方案1】:

您需要模拟 bean,用于替换服务并将其注入应用程序中的任何位置.. 如果您想进行一些验证,您必须将其注入回或在您的类中创建实例并使用模拟 bean 返回它

private val redeemService: RedeemService = mockk {
    every { validate(any()) } returns true
}

@MockBean(RedeemService::class)
fun redeemService() = redeemService

【讨论】:

  • 我想这是一个有效的解决方案。如果有其他答案,我会再等几天,否则我会接受这个答案。谢谢!
【解决方案2】:

通常,MockBean 是 NO-OP 协作者,旨在被 DI 编辑到依赖 bean 中,而不是依赖于具体的 bean 实现。

如果在测试夹具内 ~ 您测试的功能范围 ~ 您必须验证协作者调用或为其他协作者调用提供自定义响应,那么您必须注入它。

如前所述,这可能看起来像冗余,但事实并非如此,而且应该以这样的方式完成,否则 Micronaut(或任何其他这样做的框架)会有一点设计缺陷。

依赖自定义实现(在本例中为注解)充当 bean 提供者和测试中的注入点将导致不确定的行为和与框架特性的内部紧密耦合,因为您将在测试夹具中以不同方式注入依赖项从您在实际应用程序代码中执行的方式来看,应该避免这种情况。

简而言之,如果您的 bean(模拟或具体)通过 @Inject 注释进入您的测试实现,那么您可以确保它在注入到实际应用程序代码中时会以相同的方式工作,因为测试夹具是一个 bean自己。

【讨论】:

猜你喜欢
  • 2018-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-07
  • 2020-03-24
  • 2013-12-07
相关资源
最近更新 更多