Mockito/PowerMockito:奇怪的存根异常
Mockito/PowerMockito: Weird Stubbing Exception
我明白了 org.mockito.exceptions.misusing.UnfinishedStubbingException
但根据我在互联网上可以找到的所有帖子和描述,它似乎没有意义。
异常方法指出 thenReturn
可能缺失,但事实并非如此。我在下面的示例代码中故意留下了两种方式:doReturn
和 thenReturn
。 None 他们成功了。两者都具有完全相同的异常消息。
此外,没有内联模拟。我准备了所有静态 classes 并正在使用 PowerMockitoRunner。
我找不到任何出路。谁能帮我看看是怎么回事?
编辑: 我忘了说我正在使用 Mockito 1.8.5 和 PowerMockito 1.4.10。
完全异常:
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.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)
我的测试class。代码行增加 10 x 10(或类似):
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);
这对 Mockito 或 PowerMock 没有任何意义;您需要指定要模拟的特定调用。这使得这个存根未完成。以 PowerMockito when
docs 为例。
但是,Mockito 无法在这一行上判断您的存根未完成——它只能在您与其交互时引发错误,因此它仅检测错误条件稍后,在您的 mockCaptcha
方法中。
要解决此问题,请按如下方式完成 UrlUtil 存根(我指定 PowerMockito 以区别于 Mockito.doNothing,尽管看起来您的静态导入是正确的):
PowerMockito.doNothing().when(UrlUtil.class);
UrlUtil.methodYouWantToMock();
或者,要使 UrlUtil 默认抑制其所有行为,请删除 doNothing
行和 put a default answer into your mockStatic
call:
mockStatic(UrlUtil.class, RETURNS_SMART_NULLS);
我明白了 org.mockito.exceptions.misusing.UnfinishedStubbingException
但根据我在互联网上可以找到的所有帖子和描述,它似乎没有意义。
异常方法指出 thenReturn
可能缺失,但事实并非如此。我在下面的示例代码中故意留下了两种方式:doReturn
和 thenReturn
。 None 他们成功了。两者都具有完全相同的异常消息。
此外,没有内联模拟。我准备了所有静态 classes 并正在使用 PowerMockitoRunner。
我找不到任何出路。谁能帮我看看是怎么回事?
编辑: 我忘了说我正在使用 Mockito 1.8.5 和 PowerMockito 1.4.10。
完全异常:
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.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)
我的测试class。代码行增加 10 x 10(或类似):
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);
这对 Mockito 或 PowerMock 没有任何意义;您需要指定要模拟的特定调用。这使得这个存根未完成。以 PowerMockito when
docs 为例。
但是,Mockito 无法在这一行上判断您的存根未完成——它只能在您与其交互时引发错误,因此它仅检测错误条件稍后,在您的 mockCaptcha
方法中。
要解决此问题,请按如下方式完成 UrlUtil 存根(我指定 PowerMockito 以区别于 Mockito.doNothing,尽管看起来您的静态导入是正确的):
PowerMockito.doNothing().when(UrlUtil.class);
UrlUtil.methodYouWantToMock();
或者,要使 UrlUtil 默认抑制其所有行为,请删除 doNothing
行和 put a default answer into your mockStatic
call:
mockStatic(UrlUtil.class, RETURNS_SMART_NULLS);