Search code examples
javaunit-testingmockingmockitomethod-chaining

Chaining Method Calls to a Mockito Mock Returns Null


I have a following @Component with an injected object that makes a chain method call to get something, e.g.

@Component
public class MyInterceptor implements ClientHttpRequestInterceptor {

  @Autowired
  public MyProducer producer;

  @Override
  public ClientHttpResponse intercept(…) throws IOException {
    String val = producer.getProducer().getSomeVal(/*parameters*/); // LINE (1)
  }

}

And my test class is:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { MyInterceptor.class, MyProducer.class } )

public class MyInterceptorTest {

  private RestTemplate restTemplate = new RestTemplate();
  private MockRestSErviceServer mockServer;

  @Rule
  public MockitoRule rule = MockitoJUnit.rule();

  @Mock
  public MyProducer producer;

  @InjectMocks
  private MyInterceptor interceptor;

  @Before
  public void init() {
    //MockitoAnnotation.initMocks(this);
    producer = Mockito.mock(MyProducer.class, Mockito.RETURNS_DEEP_STUBS);
    // adding interceptor to RestTemplate
    mockServer = MockRestServiceServer.createServer(restTemplate);

    when(producer.getProducer().getSomeVal(null, null)).thenReturn("SomeValue");

  }

  @Test
  public void myTestMethod() {
    mockServer.expect(requestTo(/*some dummy URL*/)
      .andExpect(method(HttpMethod.GET))
      .andExcept(/*some header stuff omitted from MyInterceptor */)
      .andRespond(withSuccess(/*…*/));

    // This is going to trigger the Interceptor being invoked
    restTemplate.getForEntity("some dummy URL", String.class); // LINE (2)

    mockServer.verify();
  }
}

When the test executes LINE (2), and it invokes the interceptor, in LINE (1) I get a null pointer exception.

I was under the assumption that by enabling deep stubbing on a mock, I would be able to make a chain call and get an expected value, e.g. producer.getProducer().getSomeVal(), but it doesn't seem to be the case.

Do you know how I can get this working as expected?

P.S. I have tried different variation of adding MockitoAnnotation.initMocks() and getting rid of @Rule, or just @Autowired MyInterceptor in the test class which in this causes MyProducer not to be mocked at all, but nothing seems to work.

Note, MyProducer cannot be modified as it is from another project.


Solution

  • You've mocked the MyProducer class, but you haven't provided a when for producer.getProducer().

    So, when the code calls producer.getProducer() it will return the default mock value, which is null.

    You could try a couple of different approaches:

    when(producer.getProducer()).thenReturn(producer);
    

    I'm not sure if that will work - it might.

    Otherwise, you may be able to write a local test class that implements/extends whatever getProducer() returns, which in turn returns the appropriate test value when the correct parameters are passed to getSomeVal().