如何关闭 EasyMock 对象的录制?
我正在使用 EasyMock 对象作为 HttpServletRequest
和 HttpServletResponse
参数来测试 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);
}
当上面的代码到达调用 PortletContextFactory.createPortletContext()
的步骤时,我并不真正关心对该方法中的请求和响应对象进行什么方法调用,但是如果我在测试此方法时传入模拟请求和响应对象,我会从 EasyMock 收到错误,告诉我缺少行为定义。例如,我有一个如下所示的测试方法:
@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);
}
运行测试类时出现以下错误:
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
我假设上述错误是由于未记录在 PortletContextFactory.createPortletContext()< 中执行的方法调用引起的作为参数传入的模拟请求和响应对象上的 /code> 方法。如果这确实是这里发生的情况,那么我如何重新处理事情,以便忽略 PortletContextFactory.createPortletContext()
方法对请求和响应模拟进行的方法调用?
I am testing a servlet's doPost()
method using EasyMock objects for the HttpServletRequest
and HttpServletResponse
arguments. Within the doPost()
method I'm testing the request and response objects are used as arguments to a static method class for another class, and I want to disregard (i.e. not record as expected) any calls made on the request and response objects within this method call (it's not relevant to this test anyway). For example the doPost()
method of the servlet class I'm testing looks like this:
@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);
}
When the above code gets to the step where PortletContextFactory.createPortletContext()
is called I don't really care what method calls are made on the request and response objects within that method, but if I pass in mock request and response objects when testing this method I get errors from EasyMock telling me that there are missing behavior definitions. For example I have a test method which looks like this:
@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);
}
I get the following error when I run the test class:
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
I assume that the errors above are caused by not recording the method calls executed within the PortletContextFactory.createPortletContext()
method on the mock request and response objects passed in as arguments. If this is actually what's happening here then how can I rework things so that the method calls made on the request and response mocks by the PortletContextFactory.createPortletContext()
method are disregarded?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
尝试 Mockito http://mockito.org/。
EasyMock 使用起来要容易得多,并且不会强迫您编写所有方法调用的代码。
Try Mockito http://mockito.org/.
It is much easier to use from EasyMock, and doesn't force you to code all the method calls.
也许您需要这样的东西:
或者按照 Péter Török 的建议使用 createNiceMock() 。
Perhaps you need something like this:
Or use createNiceMock() as Péter Török suggests.
您需要模拟
PortletContextFactory.createPortletContext
调用。 EasyMock 本身不支持静态方法模拟,但 EasyMock 的 PowerMock 扩展支持。以下是您应该插入到测试中的示例代码:还有 2 个要求:
@RunWith(PowerMockRunner.class)
类级别的注释
测试用例。
@PrepareForTest(PortletContextFactory.class)
注释。欲了解更多信息,请访问:http://code.google.com/p/powermock/wiki/MockStatic
You need to mock
PortletContextFactory.createPortletContext
call. EasyMock itself does not support static method mocking, however PowerMock extension for EasyMock does. Here is the sample code you should insert into your test:There are also 2 requirements:
@RunWith(PowerMockRunner.class)
annotation at the class-level of the
test case.
@PrepareForTest(PortletContextFactory.class)
annotation at the class-level of the test case.Read more at: http://code.google.com/p/powermock/wiki/MockStatic
在类似场景中进行测试的替代方法:
要解决 EasyMock 中的静态引用问题,您可以将方法定义更改为:
在您的测试类中,您可以执行以下操作:
所有进一步的测试将使用 mockObject 来调用 Class_Under_Test 的方法。
Alternative approach to test in similar scenarios :
To get around the static reference problem in EasyMock you can change your method definition to :
In your test class you can do this :
All your further tests will use mockObject to call methods of the Class_Under_Test.
要关闭录音,请使用一个很好的模拟。从文档中:
另外,更一般地说,您想要模拟的是
createPortletContext(servletRequest, servletResponse)
。不幸的是,这是一个静态调用。要实现此模拟,请创建您自己的将返回
portletContext
的工厂,并将该工厂传递给您测试的类(最好在构造函数中)。也模拟这个工厂和
portletContext
,这样您就可以只测试这里重要的内容:您编写的代码。To turn of the recording, use a nice mock. From the documentation :
Also, more generally, what you want to mock is
createPortletContext(servletRequest, servletResponse)
. Unfortunately that's a static call.To achieve this mock, create you own factory that will return the
portletContext
, and pass this factory to you tested class (preferably in the constructor).Mock this factory and the
portletContext
too, so you can test only what matter here : the code you wrote.