【问题标题】:Mock chain call in Mockito causes NullPointerException or WrongTypeOfReturnValueMockito 中的模拟链调用导致 NullPointerException 或 WrongTypeOfReturnValue
【发布时间】:2020-08-28 09:10:41
【问题描述】:

我试图模拟这个电话:

requestTelemetryContext.getHttpRequestTelemetry().getContext().getOperation()

所以我尝试了:

OperationContext operationContext = new OperationContext(null);
RequestTelemetryContext requestTelemetryContext = mock(RequestTelemetryContext.class);
when(requestTelemetryContext.getHttpRequestTelemetry().getContext().getOperation()).thenReturn(operationContext); //causes java.lang.NullPointerException

但这给了我 java.lang.NullPointerException.

于是修改为:

    OperationContext operationContext = new OperationContext(null);
    RequestTelemetryContext requestTelemetryContext = mock(RequestTelemetryContext.class);
    RequestTelemetry requestTelemetry = new RequestTelemetry();
    when(requestTelemetryContext.getHttpRequestTelemetry()).thenReturn(requestTelemetry);
    when(requestTelemetryContext.getHttpRequestTelemetry().getContext().getOperation()).thenReturn(operationContext);

这给了我:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: getHttpRequestTelemetry() 无法返回 OperationContext getHttpRequestTelemetry() 应该返回 RequestTelemetry *** 如果您不确定为什么会出现上述错误,请继续阅读。由于上述语法的性质,可能会出现上述问题,因为:

  1. 此异常可能发生在错误编写的多线程测试中。请参阅 Mockito 常见问题解答以了解并发限制 测试。
  2. 使用 when(spy.foo()).then() 语法对间谍进行存根。存根间谍更安全-
    • 使用 doReturn|Throw() 系列方法。更多关于 Mockito.spy() 方法的 javadocs。

我不明白为什么它不能只是模拟整个链调用,我也不想像错误中所说的那样通过getHttpRequestTelemetry 返回OperationContext

编辑: 我已经尝试过建议的方法:

OperationContext operationContext = new OperationContext(null);

RequestTelemetryContext requestTelemetryContext = mock(RequestTelemetryContext.class);
RequestTelemetry requestTelemetry = mock(RequestTelemetry.class);
TelemetryContext telemetryContext = mock(TelemetryContext.class);

when(requestTelemetryContext.getHttpRequestTelemetry()).thenReturn(requestTelemetry);
when(requestTelemetry.getContext()).thenReturn(telemetryContext);
when(telemetryContext.getOperation()).thenReturn(operationContext);
ThreadContext.setRequestTelemetryContext(requestTelemetryContext);

不幸的是,RequestTelemetry requestTelemetry = mock(RequestTelemetry.class); 行导致:

Mockito 无法模拟/窥探,因为:

  • 最后一课

所以我需要找到一种方法来模拟最终课程。

【问题讨论】:

  • 也许你会设法在没有模拟的情况下构造 RequestTelemetry 类的正确实例?
  • 试过了,但我无法设置它的上下文,因为它是由受保护的方法完成的。

标签: java spring-boot mockito


【解决方案1】:

您需要在调用链的每个阶段返回模拟,并且每个模拟应该返回下一个模拟对象,例如

a().b().c().d()

所以a()应该返回一个mock,它被配置为返回一个mock b等

when(a()).thenReturn(mockA);
when(mockA.b()).thenReturn(mockB);

等等

【讨论】:

  • 谢谢,这是有道理的,我尝试了这种方法,但是出现了下一个问题,我已经在底部编辑了问题。
  • PowerMock 如果你不能将对象包装在非最终包装器中,这里可能会用到
【解决方案2】:

这里有两个问题。第一个是链式操作的模拟(requestTelemetryContext.getHttpRequestTelemetry().getContext().getOperation())。为了解决这个问题而不模拟中间的每个类,你可以在模拟时使用RETURNS_DEEP_STUBS

OperationContext operationContext = new OperationContext(null);
RequestTelemetryContext requestTelemetryContext = mock(RequestTelemetryContext.class, RETURNS_DEEP_STUBS);
when(requestTelemetryContext.getHttpRequestTelemetry().getContext().getOperation()).thenReturn(operationContext);

第二个问题是 mockito 不能模拟 final 类 - 这恐怕无法解决,你不能模拟 final 类

【讨论】:

  • 发现之前在文档中,没有按照文档中记载的方式行事,失败了。
  • 我怀疑是因为 RequestTelemetry 类:Mockito cannot mock/spy because : - final class
  • 哪个类是最终的?
  • @NirLevy , RequestTelemetry requestTelemetry = mock(RequestTelemetry.class); 由于 Final class 问题而失败。
  • @Yoda - 现在看到你的编辑,我相应地编辑了答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-21
  • 1970-01-01
  • 2017-07-05
相关资源
最近更新 更多