如何使用@MockBean 而不必再次@Inject Bean?

问题描述

是否有更简洁/优雅的方式在 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 上的注释。

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

解决方法

您需要模拟 bean,用于替换服务并将其注入应用程序中的任何地方。 /p>

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

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

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

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

正如所述,这可能看起来像冗余,但事实并非如此,应该以这种方式完成,否则 Micronaut(或任何其他框架)会存在一些设计缺陷。

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

简而言之,如果您的 bean(模拟或具体)通过 @Inject 注释进入您的测试实现,那么您可以确信它在注入到实际应用程序代码中时会起作用,因为测试装置是一个bean本身。