【问题标题】:Kotlin, Spring book, Mockito, @InjectMocks, Using different mocks than the ones createdKotlin,Spring book,Mockito,@InjectMocks,使用与创建的不同的模拟
【发布时间】:2022-01-13 02:56:46
【问题描述】:

我正在尝试测试类似的课程

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@SpringBootTest(classes = [TestConfig::class])
@ExtendWith(MockitoExtension::class)
class TotalCalculatorTests {

@Mock
lateinit var jdbcRepo: JDBCRepo

@Mock
lateinit var userCache : LoadingCache<ApproverLevel, List<Approver>>

@InjectMocks
lateinit var calculator: TotalCalculator

@Test
fun totalOrder() {
    // val calculator = TotalCalculator(userCache,jdbcRepo)
    calculator.total(ItemA(),ItemB())
    verify(jdbcRepo).getTotal()
 }
}

我收到一个错误 Actually, there were zero interactions with this mock. 但如果我取消注释 // val calculator = TotalCalculator(userCache,jdbcRepo) 它可以工作。我假设 mockito 将使用来自测试类的模拟,但这似乎不是真的。如何获取 @InjectMocks 正在使用的 JDBCRepo 实例?

【问题讨论】:

    标签: spring-boot kotlin mockito


    【解决方案1】:

    看起来您希望使用所有 bean 运行成熟的 Spring Boot 测试,但在应用程序上下文中您希望“模拟”一些真正的 bean 并提供您自己的 (mock-y) 实现。

    如果是这样,这里@Mock 的用法是错误的。 @Mock 与 spring 无关,它纯粹是模仿者的事情。它确实可以为您创建一个模拟,但它不会在 Spring Boot 的应用程序上下文中用这个模拟实现“替代”真正的实现。

    为此,请改用@MockBean 注释。这是来自春天“宇宙”的东西,它确实在引擎盖下创建了一个 mockito 驱动的模拟,但在应用程序上下文中替换了常规 bean(或者如果真正的 bean 甚至不存在,甚至只是将此模拟实现添加到应用程序上下文中) )。

    要考虑的另一件事是如何获得TotalCalculator bean(尽管您没有直接在问题中提出这个问题)。

    TotalCalculator 本身可能是 Spring Boot 为您创建的弹簧,因此如果您想运行“完整的”测试,您应该从应用程序上下文中获取此 bean 的实例,而不是创建一个自己举例。为此目的使用注释@Autowired

    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    @SpringBootTest(classes = [TestConfig::class])
    @ExtendWith(MockitoExtension::class) // you don't need this
    class TotalCalculatorTests {
    
    @MockBean
    lateinit var jdbcRepo: JDBCRepo
    
    @MockBean
    lateinit var userCache : LoadingCache<ApproverLevel, List<Approver>>
    
    @Autowired // injected by the spring test infrastructure
    lateinit var calculator: TotalCalculator
    
    @Test
    fun totalOrder() {
        // val calculator = TotalCalculator(userCache,jdbcRepo)
        calculator.total(ItemA(),ItemB())
        verify(jdbcRepo).getTotal()
     }
    }
    
    

    现在,如果您的目的确实是运行 Spring Boot 的完整微服务并进行“集成”测试,那么这一切都是正确的

    如果你只是想检查你的计算器的代码,这可能是一个矫枉过正,你可以最终使用 mockito 和普通的旧单元测试。但是在这种情况下,您甚至不需要在测试期间启动 spring(读取创建应用程序上下文),当然也不需要使用 @SpringBootTest / @MockBean/@Autowired

    所以这在很大程度上取决于这里真正需要什么样的测试

    【讨论】:

    • 是的,我想要集成测试,非常感谢您的精彩回答!!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多