Как отключить запись для объекта EasyMock? - PullRequest
4 голосов
/ 18 сентября 2010

Я тестирую метод сервлета doPost(), используя объекты EasyMock для аргументов HttpServletRequest и HttpServletResponse. В методе doPost(), который я тестирую, объекты запроса и ответа используются в качестве аргументов для статического класса метода для другого класса, и я хочу игнорировать (т.е. не записывать, как ожидалось) любые вызовы, сделанные в объектах запроса и ответа внутри вызов этого метода (это не относится к этому тесту в любом случае). Например, метод 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(), в ложные объекты запроса и ответа, переданные в качестве аргументов. Если это действительно то, что здесь происходит, то как я могу переработать вещи так, чтобы игнорировать вызовы метода, сделанные на запросах и ответах с помощью метода PortletContextFactory.createPortletContext()?

Ответы [ 5 ]

2 голосов
/ 18 сентября 2010

Попробуйте Mockito http://mockito.org/.

Это намного проще в использовании из EasyMock и не заставляет вас кодировать все вызовы методов.

1 голос
/ 18 апреля 2012

Чтобы включить запись, используйте хороший макет. Из документации:

На ложном объекте, возвращаемом createMock() поведением по умолчанию для всех Методы это бросить AssertionError для всех неожиданных вызовов методов. Если вам нужен «красивый» Mock Object, который по умолчанию разрешает все вызов метода и возврат соответствующих пустых значений (0, ноль или ложь), используйте createNiceMock() вместо.

Кроме того, в общем, вы хотите издеваться над createPortletContext(servletRequest, servletResponse). К сожалению, это статический вызов. Чтобы добиться этого макета, создайте свою собственную фабрику, которая будет возвращать portletContext, и передайте эту фабрику вам проверенному классу (предпочтительно в конструкторе). Смейся над этой фабрикой и над portletContext, чтобы ты мог проверить только то, что важно здесь: код, который ты написал.

1 голос
/ 14 апреля 2012

Альтернативный подход к тестированию в аналогичных сценариях:

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.

1 голос
/ 07 июня 2011

Нужно издеваться PortletContextFactory.createPortletContext Звонить. EasyMock сам по себе не поддерживает статический метод, но расширение PowerMock для EasyMock поддерживает. Вот пример кода, который вы должны вставить в свой тест:

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

1 голос
/ 18 сентября 2010

Возможно, вам нужно что-то вроде этого:

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

Или используйте createNiceMock (), как предлагает Петер Тёрёк.

...