Search code examples
javaunit-testingpowermockito

Why mocking a private method enters method?


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.


Solution

  • 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.