当前位置: 首页 > 知识库问答 >
问题:

莫基托。when()。thenReturn()不使用Kotlin和SpringTest处理@MockBean对象

巫坚白
2023-03-14

我在测试中使用@MockBean时使用Mockito.when(). thenBack()遇到了一些问题。

这是我的测试课:

@SpringBootTest
@AutoConfigureMockMvc
@Import(Config::class)
class ControllerTest {

    @Autowired
    private lateinit var mockMvc: MockMvc

    @MockBean
    private lateinit var kafkaPublisher: KafkaPublisher

    @Test
    fun valid payload(){
        Mockito.when(kafkaPublisher.sendEventListToKafka(anyList())).thenReturn(Unit)

        mockMvc.perform(
            post("/publish")
                .contentType(MediaType.APPLICATION_JSON)
                .content(getPayload()))
            .andExpect(status().isOk)
            .andExpect(content().string("Published 1 event(s) successfully"))
    }
}

其中getPayload()返回将使用Jackson转换为控制器对象的有效负载字符串。

这是我正在测试的控制器:

@Controller
class BumblebeeEventController {

    @Autowired
    private lateinit var kafkaPublisher: KafkaPublisher

    @PostMapping("/publish")
    fun eventIntake(@RequestBody @Valid payload: EventList) : ResponseEntity<String>{

        kafkaPublisher.sendEventListToKafka(payload)

        return ResponseEntity("Published ${payload.events.size} event(s) successfully",HttpStatus.OK)
    }
}

我现在收到Mockito的投诉。什么时候然后返回用法:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.


    at com.ControllerTest.valid payload(ControllerTest.kt:39)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
    at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

最后这里是我的KafkaPublisher:

open class KafkaPublisher @Autowired constructor(
        private val kafkaTemplate: KafkaTemplate<String, EventAvro>
)  {

    fun sendEventListToKafka(eventList: List<Event>){
        eventList.forEach {
            sendMessageToKafka(UUID.randomUUID().toString(), EventMapper.mapToEventAvro(it))
        }
    }

    fun sendMessageToKafka(uuid: String, message: EventAvro) {
        kafkaTemplate.send(kafkaTopic, uuid, message).get(3L, TimeUnit.SECONDS)
        LOGGER.info("Successfully published into kafka topic ${kafkaTopic}, message: $message")
    }

我有两个问题:

  1. 如果我取出Mockito.when.then返回MockBean KafkaPublisher尝试将事件实际发布到Kafka。我想如果它被嘲笑,它只会有一个最小的实现-例如返回null,没有任何逻辑?
  2. 为什么Mockito不使用这个KafkaPublisher类,认为这可能与它是最终的有关,所以我打开了它。不确定它还能是什么。甚至不喜欢使用真实对象而不是anyList()并且any()也不起作用?

提前谢谢

共有1个答案

冯澄邈
2023-03-14

问题1:模拟单元方法

您正在尝试存根一个方法返回单元。

Mockito.when(kafkaPublisher.sendEventListToKafka(anyList())).thenReturn(Unit)

这是不正确的。要存根空格方法,您需要使用do返回()|doThrow()|do答案()|do没什么()|doCallRealMethod()方法家族

还要注意,对于void方法,不做任何事情是默认操作。因此,正确的方法是完全删除讨论中的存根。

问题2:模拟最终方法

在Kotlin中,默认情况下所有类和方法都是final。您打开了KafkaPublisher类,但没有打开sendEventListToKafka方法。

Mockito在其默认配置中不能模拟最终方法。它可以配置为使用内联模拟制造商。这就是调用sendEventListToKafka的原始实现的原因。

然而,Kotlin通过Kotlin-spring插件提供了与spring的良好集成

由于元注释支持,使用@Configuration、@Controller、@RestController、@Service或@Repository注释的类会自动打开,因为这些注释是使用@Component元注释的。

如果用@Service注释KafkaPublisher(而不是依赖@Configuration class来生成它),它将同时打开这两个类及其方法(我的IDE甚至将open关键字标记为冗余)

 类似资料:
  • 我对莫基托有疑问。我想测试这个简单的类: 我写了这个简单的测试: 此测试运行时没有错误。我等待它没有编译,因为没有任何对userService方法的调用…

  • Mockito似乎是一个非常好的Java存根/模拟框架。唯一的问题是我找不到任何关于使用API的最佳方法的具体文档。测试中使用的常用方法包括: 当您在实践中看到Mockito的示例时,您会看到如下代码: 从我读过的所有文档中,我已经识别了几个Mockito“语法”的“模式”,这些“语法”是通过将这些方法调用像上面的示例一样链接在一起而获得的。我发现的一些常见模式有: 当/然后:当(你的方法())。

  • Mockito——我知道间谍在对象上调用实际方法,而模拟在双对象上调用方法。此外,除非有代码气味,否则要避免间谍。然而,间谍是如何工作的?我应该在什么时候使用他们?它们与模拟有什么不同?

  • 我有一个GWT应用程序,我从文本框中获取输入,检查正则表达式的值,如果匹配,然后我将该文本添加到表格中。当我为例如“你好”输入任何正确的输入时,它工作得非常好。 任何帮助都将不胜感激。

  • 我有一些困难嘲弄一些单元测试的必要依赖。我怀疑我没有正确理解如何使用Mockito when().ThenReturn()。 下面是我要测试的服务的代码部分(希望是相关的): 我的理解是,这个方法的单元测试应该如下所示: 当我运行测试时,在尝试调用appointmentTo.getCustomer()时,在appointmentConverterHelper方法中得到一个NullPointerEx

  • 试图将我的项目从Java 11更新到Java 17,在一个特定测试中,Mockito出现了一个意外错误。 投掷 不知道为什么Mockito这次考试不及格。