4

I'm using PowerMockito to mock a private method in my test.

validator = spy(new CommentValidator(form, request));
PowerMockito.when(
        validator,
        method(CommentValidator.class, "isCaptchaValid",
        HttpServletRequest.class))
    .withArguments(Mockito.any())
    .thenReturn(true);

When I run the test I get java.lang.reflect.InvocationTargetException with a NullPointerException at the second line of the isCaptchaValid method, which looks like this:

private boolean isCaptchaValid(HttpServletRequest request) {
    Captcha captcha =
        (Captcha) request.getSession().getAttribute("attribute");
    if (captcha == null) {
        log.debug(String.format("O valor do captcha da sessão esta nulo. IP: [%s]",
            IPUtil.getReaderIp(request)));
        return false;
    }
    if (captcha.isInputValid(
            request.getParameter("captcha").toString().toUpperCase())) {
        return true;
    }
    return false;
}

public final Boolean isInputValid(String pInput) {

    if (getPuzzle() == null) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("puzzle is null and invalid. Will return Boolean.FALSE");
        }
        return Boolean.FALSE;
    }

    Boolean returnValue = verifyInput(pInput);
    if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Validation of puzzle: " + returnValue);
    }
    disposePuzzle();

    return returnValue;
}

Why is the method's implementation being considered if I'm mocking its behavior? Is there a way to avoid that? The reason why I need to mock it is because I can't provide the Captcha object.

Sidney de Moraes
  • 993
  • 3
  • 11
  • 29
  • Are you sure you're declaring that correctly? [The documents](https://code.google.com/p/powermock/wiki/MockitoUsage13) show differently; you should supply the instance, the method name, and its arguments. – Makoto Jun 12 '15 at 20:12
  • Hm, I don't see anything wrong in what you posted. However, there are some pitfalls to avoid when mocking, especially when mocking private methods. You'll probably have to supply a runnable example (SSCCE, http://sscce.org/ ). – sleske Jun 12 '15 at 20:15
  • As @Makoto has pointed out you should partially mock the method like this: `PowerMockito.doReturn(true).when(validator, "isCaptchaValid", mockHttpServletRequest);` where `mockHttpServlcetRequest` is an instance and not the class - For _HttpServletRequest_ you might have a look at springs `MockHttpServletRequest` class or its builder. Using `spy` will leave the method body intact while using `mock` will usually replace the body with `return null` - that's why your call produces the NPE on `request.getSession()` invocation – Roman Vottner Jun 12 '15 at 23:31
  • Makoto and Roman, check the [API](https://powermock.googlecode.com/svn-history/r1813/docs/powermock-1.5/apidocs/org/powermock/api/mockito/PowerMockito.html). `static WithOrWithoutExpectedArguments when(Class> cls, Method method)`. I need the `WithOrWithoutExpectedArguments` interface in order to use `.withArguments`. – Sidney de Moraes Jun 15 '15 at 18:43
  • @sleske, I really enjoyed the link you sent. Never had seen that. However, it looks to me that I followed that by instinct. What exactly you think I could add to the OP? Maybe the `Captcha.isInputValid` method? I'll add it right away. Let me know if there's anything else I could add. – Sidney de Moraes Jun 15 '15 at 18:49

1 Answers1

2

Problem solved

By calling

PowerMockito.when(
        validator,
        method(CommentValidator.class, "isCaptchaValid",
        HttpServletRequest.class))
    .withArguments(Mockito.any())
    .thenReturn(true);

first the method itself is validated by PowerMockito and therefore NPE is very likely to be found.

In order to avoid that, you need to invert that logic.

doReturn(true).when(validator, "isCaptchaValid", any(HttpServletRequest.class));

It makes PowerMockito disregard the method's body and immediately return what you want.

Tom
  • 16,842
  • 17
  • 45
  • 54
Sidney de Moraes
  • 993
  • 3
  • 11
  • 29