Kotlin,Spring book,Mockito,@InjectMocks,使用与创建的不同的模拟

Posted

技术标签:

【中文标题】Kotlin,Spring book,Mockito,@InjectMocks,使用与创建的不同的模拟【英文标题】:Kotlin, Spring book, Mockito, @InjectMocks, Using different mocks than the ones created 【发布时间】: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 实例?

【问题讨论】:

【参考方案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

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

【讨论】:

是的,我想要集成测试,非常感谢您的精彩回答!!!

以上是关于Kotlin,Spring book,Mockito,@InjectMocks,使用与创建的不同的模拟的主要内容,如果未能解决你的问题,请参考以下文章

kotlin与java的比较:数据类

spring cloud books

Kotlin 原语的 Spring 验证

Spring Webflux: Kotlin DSL [片断]

在 Kotlin 中创建 Spring 的 ParameterizedTypeReference 实例

Spring Autowire Hashmap 在 kotlin 中不起作用