简体   繁体   中英

Mockito/PowerMockito: Weird Stubbing Exception

I'm getting this org.mockito.exceptions.misusing.UnfinishedStubbingException but based on all posts and descriptions I could find at internet, it doesn't seem to make sense.

The exception method states a thenReturn may be missing, but it's not. I left on purpose both ways on my example code below: doReturn and thenReturn . None of them worked. Both with the very same exception message.

Also, there are no inline mocks. I prepared all static classes and am using PowerMockitoRunner.

I can't find any way out. Any one can help me find out what's going on?

Edit: I forgot to mention I'm using Mockito 1.8.5 and PowerMockito 1.4.10.

Full exception:

    org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at org.powermock.api.mockito.internal.PowerMockitoCore.doAnswer(PowerMockitoCore.java:31)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. although stubbed methods may return mocks, you cannot inline mock creation (mock()) call inside a thenReturn method (see issue 53)

    at br.com.tests.email.EnvioCompartilhamento.mockCaptcha(EnvioCompartilhamento.java:120)
    at br.com.tests.email.EnvioCompartilhamento.setup(EnvioCompartilhamento.java:60)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at org.junit.internal.runners.MethodRoadie.runBefores(MethodRoadie.java:132)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:95)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:102)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

My test class. Code lines added 10 by 10 (or sort of):

006 --> import br.com.common.MyProperties;
import br.com.struts.email.EnvioDeEmail;
import br.com.struts.email.forms.FormularioParaCompartilhamento;
import br.com.util.UrlUtil;
010 --> import br.com.popular.commons.Publications;
import br.com.popular.commons.utils.escenic.RetrievingObjects;
import com.captcha.Captcha;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
020 --> import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;

import static org.junit.Assert.assertNull;
030 --> import static org.junit.Assert.fail;
import static org.mockito.Matchers.*;
import static org.powermock.api.mockito.PowerMockito.*;

040 --> @RunWith(PowerMockRunner.class)
@PrepareForTest({ Captcha.class, RetrievingObjects.class, UrlUtil.class })
public class EnvioCompartilhamento {

    @Mock
    private ActionMapping mapping;

    @Mock
    private HttpServletRequest request;

050 --> @Mock
    private HttpServletResponse response;

    private FormularioParaCompartilhamento formulario;

    @Before
    public void setup() throws NoSuchMethodException, NoSuchFieldException, IOException {

        mockStaticClasses();
        mockRequestBehavior();
    060 --> mockCaptcha();
        mockResponse();
        formulario = new FormularioParaCompartilhamento();
    }

    @Test
    public void compartilhamentoComSucesso() {

        formulario.setEmailTo("teste@teste.com");
        formulario.setIdArtigo("12345");
    070 --> formulario.setIsArtigo(true);
        formulario.setMessage("Corpo do email");
        formulario.setTitulo("Titulo");
        formulario.setUrl("http://www.google.com");
        formulario.setCaptcha("ABCD");

        EnvioDeEmail email = new EnvioDeEmail();
        final ActionForward resultado = email.compartilhamento(mapping, formulario, request, response);

        assertNull(resultado);
    080 --> }

    112 --> private void mockRequestBehavior() {

        when(request.getMethod()).thenReturn("POST");
        when(request.getHeader("X-FORWARDED-FOR")).thenReturn("User IP");
    }

    private void mockCaptcha() {

    120 --> HttpSession session = mock(HttpSession.class);
        doReturn(session).when(request).getSession();
        Captcha captcha = Mockito.mock(Captcha.class);
        doReturn(captcha).when(session).getAttribute("captcha");
        doReturn(true).when(captcha).isInputValid(anyString());
    }

    private void mockStaticClasses() {

        final MyProperties myProperties = mock(MyProperties.class);
    130 --> mockStatic(RetrievingObjects.class);
        when(RetrievingObjects.componentFromPublicationAtSystemScope(any(Publications.class), eq("EmailProperties"), eq(MyProperties.class))).
            thenReturn(myProperties);
        mockStatic(UrlUtil.class);
        doNothing().when(UrlUtil.class);
    }

    private void mockResponse() throws IOException {

        PrintWriter writer = mock(PrintWriter.class);
    140 --> doReturn(writer).when(response).getWriter();
    }

}
doNothing().when(UrlUtil.class);

This doesn't mean anything to Mockito or PowerMock; you need to specify the specific call you want to mock. That makes this stubbing unfinished . See the PowerMockito when docs as an example.

However, Mockito can't tell on this line that your stubbing is unfinished—it can only raise an error when you interact with it, so it only detects the error condition later, in your mockCaptcha method.

To fix this, either finish your UrlUtil stub as follows (I specify PowerMockito to distinguish from Mockito.doNothing, though it looks like you have your static imports correct):

PowerMockito.doNothing().when(UrlUtil.class);
UrlUtil.methodYouWantToMock();

Or, to make UrlUtil suppress all its behavior by default, remove that doNothing line and put a default answer into your mockStatic call :

mockStatic(UrlUtil.class, RETURNS_SMART_NULLS);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM