【问题标题】:Mockito RETURNS_DEEP_STUBS throws nullpointer exceptionMockito RETURNS_DEEP_STUBS 抛出空指针异常
【发布时间】:2021-12-28 10:43:45
【问题描述】:

我在模拟 ClientResponseWrapper 类时遇到了一些问题。我已经模拟了它并添加了“RETURNS_DEEP_STUBS”参数以便能够模拟链式调用。我不断收到“NullPointerException”,不知道为什么。 你能帮帮我吗?

代码如下:

package com.service.external_data.application.synchronize_bookings;

import com.service.external_data.domain.BookingUpdateQueueItem;
import com.service.external_data.domain.repository.BookingUpdateQueueRepository;
import com.service.external_data.domain.repository.KeyValueRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;


@ExtendWith(MockitoExtension.class)
public class Transaction2Test {

    @Mock
    private KeyValueRepository keyValueRepository;

    @Mock
    private BookingUpdateQueueRepository bookingUpdateQueueRepository;;

    @Mock
    private BookingClient bookingClient;

    @Captor
    private ArgumentCaptor<List<BookingUpdateQueueItem>> bookingUpdateQueueItemCaptor;

    @InjectMocks
    private Transaction transaction;

    @Test
    public void testRunSuccessResponse() {
        Integer startIndex = 456;
        when(keyValueRepository.getFromIndex()).thenReturn(startIndex);

        ClientResponseWrapper<BookingUpdateResponse> clientResponse = mock(ClientResponseWrapper.class, RETURNS_DEEP_STUBS);

        BookingUpdateDto bookingUpdateDto = mock(BookingUpdateDto.class);
        when(bookingUpdateDto.getBookingNumber()).thenReturn("12345");

        List<BookingUpdateDto> bookingUpdateDtos = List.of(bookingUpdateDto);

        when(clientResponse.getResponseBody().getData()).thenReturn(bookingUpdateDtos);
        when(clientResponse.getStatusCode()).thenReturn(HttpStatus.OK);

        List<BookingUpdateDto> bookings = mock(List.class);
        BookingUpdateResponse bookingUpdateResponse = mock(BookingUpdateResponse.class);
        when(clientResponse.getResponseBody()).thenReturn(bookingUpdateResponse);
        when(bookingUpdateResponse.getData()).thenReturn(bookings);

        when(bookingClient.requestBookingUpdates(startIndex)).thenReturn(clientResponse);

        Integer nextIndex = 678;
        when(bookingUpdateResponse.getNextFrom()).thenReturn(nextIndex);

        transaction.run();

        verify(bookingUpdateQueueRepository).saveAll(bookingUpdateQueueItemCaptor.capture());

        Integer listSize = bookingUpdateQueueItemCaptor.getValue().size();

        assertEquals(1, listSize);
        verify(keyValueRepository).setFromIndex(nextIndex);
    }
}

例外情况是: java.lang.NullPointerException 在行: "当(clientResponse.getResponseBody().getData()).thenReturn(bookingUpdateDtos);"

完整的堆栈跟踪:

java.lang.NullPointerException
    at com.service.external_data.application.synchronize_bookings.Transaction2Test.testRunSuccessResponse(Transaction2Test.java:60)
    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:1540)
    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:1540)
    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 org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
    at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
    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.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy5.stop(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
    at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

【问题讨论】:

  • 你必须先设置响应体对象。例如 when(clientResponse.getResponseBody()).thenReturn(Data 对象);
  • 但是“RETURNS_DEEP_STUBS”功能不应该处理模拟的所有中间调用吗?
  • 请将完整的堆栈跟踪添加到您的问题中。
  • 您可以查看 Mockito 对干净代码和验证的看法。有一个与之相关的警告。链接:javadoc.io/doc/org.mockito/mockito-core/2.6.9/org/mockito/…
  • ClientResponseWrapper 是你写的一个类,是public 和非final? (或者它是一个接口?)getResponseBody() 也是public 和非final? 60号线是哪条线?最后,你为什么嘲笑getResponseBody().getData(),然后用你自己的bookingUpdateResponse代替它?

标签: java unit-testing junit mockito


【解决方案1】:

我能够找到解决问题的方法。正如 Jeff Bowman 所提到的,我在嘲笑“bookingUpdateResponse.getData()”“两次”的响应,我认为因此引发了异常。我能够在没有“RETURNS_DEEP_STUBS”的情况下编写测试(通过模拟中间调用):

结果:

    @Test
    public void testRunSuccessResponse() {
        Integer startIndex = 456;
        when(keyValueRepository.getFromIndex()).thenReturn(startIndex);

        ClientResponseWrapper<BookingUpdateResponse> clientResponse = mock(ClientResponseWrapper.class);

        BookingUpdateDto bookingUpdateDto = mock(BookingUpdateDto.class);
        when(bookingUpdateDto.getBookingNumber()).thenReturn("12345");

        List<BookingUpdateDto> bookingUpdateDtos = List.of(bookingUpdateDto);

        when(clientResponse.getStatusCode()).thenReturn(HttpStatus.OK);

        BookingUpdateResponse bookingUpdateResponse = mock(BookingUpdateResponse.class);
        when(clientResponse.getResponseBody()).thenReturn(bookingUpdateResponse);
        when(bookingUpdateResponse.getData()).thenReturn(bookingUpdateDtos);

        when(bookingClient.requestBookingUpdates(startIndex)).thenReturn(clientResponse);

        Integer nextIndex = 678;
        when(bookingUpdateResponse.getNextFrom()).thenReturn(nextIndex);

        transaction.run();

        verify(bookingUpdateQueueRepository).saveAll(bookingUpdateQueueItemCaptor.capture());

        Integer listSize = bookingUpdateQueueItemCaptor.getValue().size();

        assertEquals(1, listSize);
        verify(keyValueRepository).setFromIndex(nextIndex);
    }

感谢大家的帮助!

【讨论】:

    猜你喜欢
    • 2020-03-13
    • 1970-01-01
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-22
    • 2020-08-10
    相关资源
    最近更新 更多