1

Having had many issues in unit testing my application please help address my simplest issue - mocking void methods, per a few stack overflow articles and common references in articles. My Java code in a JBPM application WorkItemHandler follows the pattern of

public class EmailNotificationWorkItemHandler() extends AbstractLogOrThrowWorkItemHandler {
  private static Utils utils = new Utils() ; 

  public void executeWorkItem(WorkItem workItem, WorkItemManager manager) { 
    if (<condition>) {
            utils.insertAmsErrors(<param>, <param>, <param>, <param>, <param>);         
            return;
        }
 ....
     try { 
         RequiredParameterValidator.validate(this.getClass(), workItem);
...
   }

I have been trying to stub Utils and its insertAmsErrors method to test RequiredParameterValidator.validate used later in executeWorkItem. The references imply that the void call to utils and its insertAmsErrors method could be a very basic stub of

      Utils mockUtils = mock(Utils.class);

      doAnswer(new Answer<Void>() {
          public Void answer(InvocationOnMock invocation) {
                 Object[] args = invocation.getArguments();
                 //Mock mock = (Mock) invocation.getMock();  Doesn't solve NPE
                 return null;
            }         
      }).when(mockUtils).insertAmsErrors(any(), any(), any(), any(), any()); // NPE here

but the stub throws a null pointer exception at "NPE here". Utils.insertAmsErrors signature is

public void insertAmsErrors(String id, ErrorCode error, String errorMsg, 
          StackTraceElement [] stackTrace, long processId) 

I also considered using a spy, per another answer in the same posting, but my unit test is not calling insertAmsErrors on an instance of Utils, but rather executeWorkItem in EmailNotificationWorkItemHandler is making such a call.

How should I correctly mock the Utils class and its insertAmsErrors method so that I can test RequiredParameterValidator.validate in executeWorkItem?

Dr Dave
  • 550
  • 1
  • 6
  • 22

1 Answers1

3

The problem is not related to the fact that you're mocking a void method. The problem lies in your usage of the any() method.

when(mockUtils).insertAmsErrors(any(), any(), any(), any(), any());  

The 5th required parameter is of type long and for this reason you should use the dedicated anyLong() method for it instead. This applies to all primitive types: anyInt() for int parameters, anyBoolean() for boolean parameters and so on...

The reason behind this is that Mockito's any() method returns null by design, inducing a NPE when there is an attempt to unbox it. See this related answer for more details about it.

(On a side note) Another potential problem could rise by the fact that your utils field is static, private and with an hardcoded dependency. This is not a good target for stubbing and you should probably rethink this by making, for example, the field non-static and then injecting the dependency.

public class EmailNotificationWorkItemHandler() extends AbstractLogOrThrowWorkItemHandler {
    private Utils utils;
    
    public EmailNotificationWorkItemHandler(Utils utils){
        this.utils = utils;
    }
    ...
}  

This way you can pass the mocked object during your unit tests.

cidra
  • 374
  • 1
  • 4
  • 16