Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mockito ArgumentCaptor gives NullpointerException on verify()

I'm currently trying to create tests for our Servlets. I've mocked HttpServletRequest, HttpServletResponse and an object serving as a database handler. In the test for the doPost method, my wish is to compare the values from the Json object and the ArrayList sent to the database object.

The servlet:

public class WidgetStatusServlet extends HttpServlet {

private DBController db = new DBController();

    @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    response.setContentType("application/json");
    JsonParser parser = new JsonParser();
    JsonElement tradeElement = parser.parse(request.getParameter("widgetdata"));
    JsonArray json = tradeElement.getAsJsonArray();
    Gson gson = new Gson();
    Type listType = new TypeToken<List<WidgetStatus>>() {
    }.getType();
    ArrayList<WidgetStatus> widgets = gson.fromJson(json, listType);

    Iterator<WidgetStatus> iterator = widgets.iterator();
    System.out.println("Widgets");
    while (iterator.hasNext()) {
        WidgetStatus node = (WidgetStatus) iterator.next();
        System.out.println(node);
    }

    db.addWidgetStatus(widgets);

}

The test:

public class WidgetStatusServletTest {

@Captor
private ArgumentCaptor<ArrayList<WidgetStatus>> captor;

private DBController dbMock = mock(DBController.class);
private HttpServletRequest request = mock(HttpServletRequest.class);
private HttpServletResponse response = mock(HttpServletResponse.class);
Repository repository = mock(Repository.class);`


    @Test
public void doPost_ShouldVerifyWidgetsIsProvided() throws Exception {
    final WidgetStatus widget1 = new WidgetStatus("id1", "div_id1", "5", "5", "1", "2", false);
    final WidgetStatus widget2 = new WidgetStatus("id2", "div_id2", "2", "1", "3", "1", true);

    when(request.getParameter("widgetdata")).thenAnswer(new Answer<String>() {
        @Override
        public String answer(InvocationOnMock invocation) throws Throwable {
            ArrayList<WidgetStatus> array = new ArrayList<WidgetStatus>();
            array.add(widget1);
            array.add(widget2);
            String json = new Gson().toJson(array);
            return json;
        }
    });
    new WidgetStatusServlet().doPost(request, response);
    verify(dbMock).addWidgetStatus(captor.capture());
    assertNotNull(captor.getAllValues());


}

When I'm running the test it gives me NullpointerException at the line

        verify(dbMock).addWidgetStatus(captor.capture());

What am I doing wrong? I've looked at several examples with the same usage of the ArgumentCaptor. Perhaps this is just a minor error?

like image 883
frods Avatar asked Apr 26 '14 11:04

frods


1 Answers

If you use the MockitoJUnitRunner to run your test, then an ArgumentCaptor will be created for you, and there's no need to initialise it explicitly. If you do that, then you can also use the @Mock annotation to create your mock objects, that is, you don't need the mock static method any more. Your test class would then begin like this.

@RunWith(MockitoJUnitRunner.class)
public class WidgetStatusServletTest {

    @Captor private ArgumentCaptor<ArrayList<WidgetStatus>> captor;
    @Mock private DBController mockController;
    @Mock private HttpServletRequest mockRequest;
    @Mock private HttpServletResponse mockResponse;
    @Mock private Repository mockRepository;

This question addresses the issue of whether to use MockitoJUnitRunner, or an explicit call to MockitoAnnotations.initMocks.

Just a side note - your test methods will be much easier to read if you use variable names that clearly indicate that your objects are mocks, like I've done here. Otherwise, in a long test class with many different variables, it's easy to lose track of which variables reference mocks, and which reference "real" objects.

like image 185
Dawood ibn Kareem Avatar answered Sep 30 '22 08:09

Dawood ibn Kareem