Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock chain call in Mockito causes NullPointerException or WrongTypeOfReturnValue

I'm trying to mock this call:

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

So I tried that:

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

but that gives me java.lang.NullPointerException.

So modified it into:

    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);

that gives me:

org.mockito.exceptions.misusing.WrongTypeOfReturnValue: OperationContext cannot be returned by getHttpRequestTelemetry() getHttpRequestTelemetry() should return RequestTelemetry *** If you're unsure why you're getting above error read on. Due to the nature of the syntax above problem might occur because:

  1. This exception might occur in wrongly written multi-threaded tests. Please refer to Mockito FAQ on limitations of concurrency testing.
  2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
    • with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.

I do not understand why it can't just mock the whole chain call and I am not trying to return OperationContext by getHttpRequestTelemetry like it states in the error.

EDIT: I've tried suggested approach:

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);

unfortunately that line RequestTelemetry requestTelemetry = mock(RequestTelemetry.class); causes:

Mockito cannot mock/spy because :

  • final class

so i need to find a way to mock final class.

like image 480
Yoda Avatar asked Oct 26 '25 08:10

Yoda


2 Answers

You have two issues here. the first one is with the mock of chained operations (requestTelemetryContext.getHttpRequestTelemetry().getContext().getOperation()). to solve this without mocking every class in the middle, you can use RETURNS_DEEP_STUBS when mocking:

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

The second issue is that mockito cannot mock final classes - this is I'm afraid not solvable, you can't mock a final class

like image 132
Nir Levy Avatar answered Oct 28 '25 20:10

Nir Levy


You need to return the mock at each stage of your call chain, and each mock should return the next mock object e.g.

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

so a() should return a mock, which is configured to return a mock b etc.

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

etc.

like image 39
Brian Agnew Avatar answered Oct 28 '25 20:10

Brian Agnew