Java 如何关闭EasyMock对象的录制?
我正在为Java 如何关闭EasyMock对象的录制?,java,unit-testing,mocking,easymock,Java,Unit Testing,Mocking,Easymock,我正在为HttpServletRequest和HttpServletResponse参数使用EasyMock对象测试servlet的doPost()方法。在doPost()方法中,我正在测试的请求和响应对象被用作另一个类的静态方法类的参数,我希望忽略(即,不按预期记录)在此方法调用中对请求和响应对象进行的任何调用(无论如何,它与此测试无关)。例如,我正在测试的servlet类的doPost()方法如下所示: @Override protected void doPost(final HttpSe
HttpServletRequest
和HttpServletResponse
参数使用EasyMock对象测试servlet的doPost()
方法。在doPost()
方法中,我正在测试的请求和响应对象被用作另一个类的静态方法类的参数,我希望忽略(即,不按预期记录)在此方法调用中对请求和响应对象进行的任何调用(无论如何,它与此测试无关)。例如,我正在测试的servlet类的doPost()
方法如下所示:
@Override
protected void doPost(final HttpServletRequest servletRequest,
final HttpServletResponse servletResponse)
throws ServletException, IOException
{
// handle an "updateFolder" event
String eventParameter = servletRequest.getParameter("event");
if ("updateFolder".equalsIgnoreCase(eventParameter))
{
// update the news documents folder settings
String folderId = servletRequest.getParameter("folderId");
IPortletContext portletContext = PortletContextFactory.createPortletContext(servletRequest, servletResponse);
IPortletResponse portletResponse = portletContext.getResponse();
portletResponse.setSettingValue(SettingType.CommunityPortlet, "NEWS_DOCUMENTS_FOLDER_ID", folderId);
}
// redirect to the appropriate URL
servletResponse.sendRedirect(redirectUrl);
}
@Test
public void testPostWithUpdate()
throws Exception
{
// create mock objects and record their expected calls
HttpServletRequest mockServletRequest = createMock(HttpServletRequest.class);
HttpServletResponse mockServletResponse = createMock(HttpServletResponse.class);
IPortletResponse mockPortletResponse = createMock(IPortletResponse.class);
IPortletContext mockPortletContext = createMock(IPortletContext.class);
expect(mockServletRequest.getContextPath()).andReturn(null);
expect(mockServletRequest.getParameter("event")).andReturn("updateFolder");
expect(mockServletRequest.getParameter("folderId")).andReturn(null);
expect(PortletContextFactory.createPortletContext(mockServletRequest, mockServletResponse)).andReturn(mockPortletContext);
expect(mockPortletContext.getResponse()).andReturn(mockPortletResponse);
mockPortletResponse.setSettingValue(SettingType.CommunityPortlet, "NEWS_DOCUMENTS_FOLDER_ID", null);
mockServletResponse.sendRedirect(EasyMock.anyObject(String.class));
// take the mock objects out of record state
replay(mockPortletContext, mockPortletResponse, mockServletRequest, mockServletResponse);
// instantiate an object of the class and run the method we want to test
ControllerServlet controllerServlet = new ControllerServlet();
controllerServlet.doPost(mockServletRequest, mockServletResponse);
// verify that our mocks behaved as expected
verify(mockPortletContext, mockPortletResponse, mockServletRequest, mockServletResponse);
}
expect(mockServletRequest.getCharacterEncoding()).andReturn("UTF-8");
当上面的代码到达调用PortletContextFactory.createPortletContext()
的步骤时,我并不真正关心对该方法中的请求和响应对象调用什么方法,但是,如果在测试此方法时传入模拟请求和响应对象,EasyMock会告诉我缺少行为定义,这会导致错误。例如,我有一个测试方法,如下所示:
@Override
protected void doPost(final HttpServletRequest servletRequest,
final HttpServletResponse servletResponse)
throws ServletException, IOException
{
// handle an "updateFolder" event
String eventParameter = servletRequest.getParameter("event");
if ("updateFolder".equalsIgnoreCase(eventParameter))
{
// update the news documents folder settings
String folderId = servletRequest.getParameter("folderId");
IPortletContext portletContext = PortletContextFactory.createPortletContext(servletRequest, servletResponse);
IPortletResponse portletResponse = portletContext.getResponse();
portletResponse.setSettingValue(SettingType.CommunityPortlet, "NEWS_DOCUMENTS_FOLDER_ID", folderId);
}
// redirect to the appropriate URL
servletResponse.sendRedirect(redirectUrl);
}
@Test
public void testPostWithUpdate()
throws Exception
{
// create mock objects and record their expected calls
HttpServletRequest mockServletRequest = createMock(HttpServletRequest.class);
HttpServletResponse mockServletResponse = createMock(HttpServletResponse.class);
IPortletResponse mockPortletResponse = createMock(IPortletResponse.class);
IPortletContext mockPortletContext = createMock(IPortletContext.class);
expect(mockServletRequest.getContextPath()).andReturn(null);
expect(mockServletRequest.getParameter("event")).andReturn("updateFolder");
expect(mockServletRequest.getParameter("folderId")).andReturn(null);
expect(PortletContextFactory.createPortletContext(mockServletRequest, mockServletResponse)).andReturn(mockPortletContext);
expect(mockPortletContext.getResponse()).andReturn(mockPortletResponse);
mockPortletResponse.setSettingValue(SettingType.CommunityPortlet, "NEWS_DOCUMENTS_FOLDER_ID", null);
mockServletResponse.sendRedirect(EasyMock.anyObject(String.class));
// take the mock objects out of record state
replay(mockPortletContext, mockPortletResponse, mockServletRequest, mockServletResponse);
// instantiate an object of the class and run the method we want to test
ControllerServlet controllerServlet = new ControllerServlet();
controllerServlet.doPost(mockServletRequest, mockServletResponse);
// verify that our mocks behaved as expected
verify(mockPortletContext, mockPortletResponse, mockServletRequest, mockServletResponse);
}
expect(mockServletRequest.getCharacterEncoding()).andReturn("UTF-8");
我在运行测试类时遇到以下错误:
com.plumtree.openfoundation.util.XPIllegalStateException: missing behavior definition for the preceding method call getCharacterEncoding()
at com.plumtree.openfoundation.util.XPException.GetInstance(XPException.java:397)
at com.plumtree.openfoundation.util.XPException.GetInstance(XPException.java:350)
at com.plumtree.openfoundation.web.XPRequest.InitRequest(XPRequest.java:201)
at com.plumtree.openfoundation.web.XPRequest.<init>(XPRequest.java:111)
at com.plumtree.remote.portlet.PortletContextFactory.createPortletContext(PortletContextFactory.java:32)
at com.abc.servlet.ControllerServletTest.testPostWithUpdate(ControllerServletTest.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.IllegalStateException: missing behavior definition for the preceding method call getCharacterEncoding()
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:43)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:73)
at $Proxy4.setCharacterEncoding(Unknown Source)
at com.plumtree.openfoundation.web.XPRequest.InitRequest(XPRequest.java:135)
... 25 more
com.plumtree.openfoundation.util.XPIllegalStateException:前面的方法调用getCharacterEncoding()缺少行为定义
位于com.plumtree.openfoundation.util.XPException.GetInstance(XPException.java:397)
位于com.plumtree.openfoundation.util.XPException.GetInstance(XPException.java:350)
位于com.plumtree.openfoundation.web.XPRequest.InitRequest(XPRequest.java:201)
位于com.plumtree.openfoundation.web.XPRequest.(XPRequest.java:111)
位于com.plumtree.remote.portlet.PortletContextFactory.createPortletContext(PortletContextFactory.java:32)
位于com.abc.servlet.ControllerServletTest.testPostWithUpdate(ControllerServletTest.java:31)
在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处
位于sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)中
位于java.lang.reflect.Method.invoke(Method.java:597)
位于org.junit.runners.model.FrameworkMethod$1.runReflectVeCall(FrameworkMethod.java:44)
位于org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
位于org.junit.runners.model.FrameworkMethod.invokeeexplosive(FrameworkMethod.java:41)
位于org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
位于org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
位于org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
位于org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
位于org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
位于org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
访问org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
位于org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
位于org.junit.runners.ParentRunner.run(ParentRunner.java:236)
位于org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
位于org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
位于org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
位于org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
位于org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
位于org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
原因:java.lang.IllegalStateException:前面的方法调用getCharacterEncoding()缺少行为定义
位于org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:43)
位于org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:73)
在$Proxy4.setCharacterEncoding处(未知源)
位于com.plumtree.openfoundation.web.XPRequest.InitRequest(XPRequest.java:135)
... 25多
我假设上述错误是由于没有记录在作为参数传入的模拟请求和响应对象上的PortletContextFactory.createPortletContext()
方法中执行的方法调用造成的。如果这里确实发生了这种情况,那么我如何重新处理这些事情,以便忽略由PortletContextFactory.createPortletContext()
方法对请求和响应mock进行的方法调用?尝试Mockito
从EasyMock中使用它更容易,而且不会强制您编写所有方法调用的代码。也许您需要这样的东西:
@Override
protected void doPost(final HttpServletRequest servletRequest,
final HttpServletResponse servletResponse)
throws ServletException, IOException
{
// handle an "updateFolder" event
String eventParameter = servletRequest.getParameter("event");
if ("updateFolder".equalsIgnoreCase(eventParameter))
{
// update the news documents folder settings
String folderId = servletRequest.getParameter("folderId");
IPortletContext portletContext = PortletContextFactory.createPortletContext(servletRequest, servletResponse);
IPortletResponse portletResponse = portletContext.getResponse();
portletResponse.setSettingValue(SettingType.CommunityPortlet, "NEWS_DOCUMENTS_FOLDER_ID", folderId);
}
// redirect to the appropriate URL
servletResponse.sendRedirect(redirectUrl);
}
@Test
public void testPostWithUpdate()
throws Exception
{
// create mock objects and record their expected calls
HttpServletRequest mockServletRequest = createMock(HttpServletRequest.class);
HttpServletResponse mockServletResponse = createMock(HttpServletResponse.class);
IPortletResponse mockPortletResponse = createMock(IPortletResponse.class);
IPortletContext mockPortletContext = createMock(IPortletContext.class);
expect(mockServletRequest.getContextPath()).andReturn(null);
expect(mockServletRequest.getParameter("event")).andReturn("updateFolder");
expect(mockServletRequest.getParameter("folderId")).andReturn(null);
expect(PortletContextFactory.createPortletContext(mockServletRequest, mockServletResponse)).andReturn(mockPortletContext);
expect(mockPortletContext.getResponse()).andReturn(mockPortletResponse);
mockPortletResponse.setSettingValue(SettingType.CommunityPortlet, "NEWS_DOCUMENTS_FOLDER_ID", null);
mockServletResponse.sendRedirect(EasyMock.anyObject(String.class));
// take the mock objects out of record state
replay(mockPortletContext, mockPortletResponse, mockServletRequest, mockServletResponse);
// instantiate an object of the class and run the method we want to test
ControllerServlet controllerServlet = new ControllerServlet();
controllerServlet.doPost(mockServletRequest, mockServletResponse);
// verify that our mocks behaved as expected
verify(mockPortletContext, mockPortletResponse, mockServletRequest, mockServletResponse);
}
expect(mockServletRequest.getCharacterEncoding()).andReturn("UTF-8");
或者按照péter Török的建议使用createNiceMock()。您需要模拟
PortletContextFactory.createPortletContext
调用。EasyMock本身不支持静态方法模拟,但是EasyMock的PowerMock扩展支持静态方法模拟。以下是您应该插入测试的示例代码:
mockStatic(PortletContextFactory.class);
expect(PortletContextFactory.createPortletContext(mockServletRequest, mockServletResponse)).andReturn(mockPortletContext);
replay(PortletContextFactory.class);
还有两项要求:
@RunWith(PowerMockRunner.class)
类级别的注释
测试用例@PrepareForTest(PortletContextFactory.class)
注释更多信息请访问:在类似场景中测试的替代方法:
class Class_Under_Test {
public void A() {
B b = C.create(); //create is static
D d = e.(b);
}
}
要解决EasyMock中的静态引用问题,可以将方法定义更改为:
@VisibleForTesting
B create() {
return C.create();
}
public A() {
B b = create();
D d = e.(b);
}
在测试类中,您可以执行以下操作:
Class testSomething {
private Mock_Class_Under_Test mockOject;//Class Defined below
private B mockB;
@Override
void setup() {
mockB =createMock(B.class);
}
private class Mock_Class_Under_Test extends Class_Under_Test {
@Override
B create() {
return mockB;
}
}
public void testA() {
//No need to put expectation on static call as create() will always return mock.
expect(e.something(mockB)).andReturn(somethingElse);
}
}
所有进一步的测试都将使用mockObject来调用类_下的_测试的方法。要开始录制,请使用一个好的mock。从文件中: 在由
createMock()
返回的模拟对象上,所有
方法是为所有意外的方法调用抛出一个AssertionError
。
如果您想要一个默认允许所有
方法调用并返回适当的空值(0、null或false),