代码之家  ›  专栏  ›  技术社区  ›  James Adams

如何关闭EasyMock对象的录制?

  •  4
  • James Adams  · 技术社区  · 15 年前

    我正在测试一个servlet的 doPost() HttpServletRequest HttpServletResponse 论据。在 我正在测试的方法请求和响应对象被用作另一个类的静态方法类的参数,我想忽略(即不按预期记录)在这个方法调用中对请求和响应对象所做的任何调用(反正它与此测试无关)。例如 doPost() 我正在测试的servlet类的方法如下所示:

    @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
    

    我假设上面的错误是由于没有记录在 POrtleContextFactory.createPortletContext() 方法被忽视了?

    5 回复  |  直到 14 年前
        1
  •  2
  •   Eran Harel    15 年前

    试试莫基托 http://mockito.org/

    从EasyMock使用它要容易得多,并且不强制您编写所有方法调用的代码。

        2
  •  1
  •   jbindel    15 年前

    也许你需要这样的东西:

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

        3
  •  1
  •   Volo    14 年前

    PortletContextFactory.createPortletContext 打电话。EasyMock本身不支持静态方法模拟,但是EasyMock的PowerMock扩展支持。以下是应插入测试的示例代码:

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

    还有两个要求:

    1. @RunWith(PowerMockRunner.class) 类级别的注释 测试用例。
    2. 使用 @PrepareForTest(PortletContextFactory.class)

    更多信息请访问: http://code.google.com/p/powermock/wiki/MockStatic

        4
  •  1
  •   Deepanshu Malik    14 年前

    类似情况下的替代测试方法:

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

        5
  •  1
  •   Volo    14 年前

    createMock() 所有人的默认行为 AssertionError 对于所有意外的方法调用。 方法调用并返回适当的空值(0、null或false), createNiceMock() 相反。

    而且,更一般地说,你想嘲笑的是 createPortletContext(servletRequest, servletResponse) 要实现此模拟,请创建自己的工厂,该工厂将返回 portletContext ,并将此工厂传递给测试的类(最好在构造函数中)。 portletContext 因此,您只能测试这里重要的东西:您编写的代码。