如何关闭 EasyMock 对象的录制?

发布于 2024-09-24 02:30:43 字数 6150 浏览 6 评论 0原文

我正在使用 EasyMock 对象作为 HttpServletRequestHttpServletResponse 参数来测试 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

暖风昔人 2024-10-01 02:30:43

尝试 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.

帅气尐潴 2024-10-01 02:30:43

也许您需要这样的东西:

expect(mockServletRequest.getCharacterEncoding()).andReturn("UTF-8");

或者按照 Péter Török 的建议使用 createNiceMock() 。

Perhaps you need something like this:

expect(mockServletRequest.getCharacterEncoding()).andReturn("UTF-8");

Or use createNiceMock() as Péter Török suggests.

眉黛浅 2024-10-01 02:30:43

您需要模拟 PortletContextFactory.createPortletContext 调用。 EasyMock 本身不支持静态方法模拟,但 EasyMock 的 PowerMock 扩展支持。以下是您应该插入到测试中的示例代码:

mockStatic(PortletContextFactory.class);     
expect(PortletContextFactory.createPortletContext(mockServletRequest, mockServletResponse)).andReturn(mockPortletContext);
replay(PortletContextFactory.class);

还有 2 个要求:

  1. 使用
    @RunWith(PowerMockRunner.class)
    类级别的注释
    测试用例。
  2. 在测试用例的类级别使用 @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:

mockStatic(PortletContextFactory.class);     
expect(PortletContextFactory.createPortletContext(mockServletRequest, mockServletResponse)).andReturn(mockPortletContext);
replay(PortletContextFactory.class);

There are also 2 requirements:

  1. Use the
    @RunWith(PowerMockRunner.class)
    annotation at the class-level of the
    test case.
  2. Use the @PrepareForTest(PortletContextFactory.class) annotation at the class-level of the test case.

Read more at: http://code.google.com/p/powermock/wiki/MockStatic

那伤。 2024-10-01 02:30:43

在类似场景中进行测试的替代方法:

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 来调用 Class_Under_Test 的方法。

Alternative approach to test in similar scenarios :

class Class_Under_Test {
  public void A() {
    B b = C.create(); //create is static
    D d = e.(b);
  }
}

To get around the static reference problem in EasyMock you can change your method definition to :

@VisibleForTesting
B create() {
  return C.create();
}

public A() {
  B b = create();
  D d = e.(b); 
}

In your test class you can do this :

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);   
  }
}

All your further tests will use mockObject to call methods of the Class_Under_Test.

零時差 2024-10-01 02:30:43

要关闭录音,请使用一个很好的模拟。从文档中:

createMock()返回的模拟对象上,所有的默认行为
方法的目的是为所有意外的方法调用抛出一个 AssertionError
如果您想要一个“漂亮”的模拟对象,默认情况下允许所有
方法调用并返回适当的空值(0、null 或 false),
请改用createNiceMock()

另外,更一般地说,您想要模拟的是createPortletContext(servletRequest, servletResponse)。不幸的是,这是一个静态调用。
要实现此模拟,请创建您自己的将返回 portletContext 的工厂,并将该工厂传递给您测试的类(最好在构造函数中)。
也模拟这个工厂和 portletContext,这样您就可以只测试这里重要的内容:您编写的代码。

To turn of the recording, use a nice mock. From the documentation :

On a Mock Object returned by createMock() the default behavior for all
methods is to throw an AssertionError for all unexpected method calls.
If you would like a "nice" Mock Object that by default allows all
method calls and returns appropriate empty values (0, null or false),
use createNiceMock() instead.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文