4

および引数doPost()に EasyMock オブジェクトを使用して、サーブレットのメソッドをテストしています。テストしているメソッド内で、リクエスト オブジェクトとレスポンス オブジェクトが別のクラスの静的メソッド クラスへの引数として使用されます。このメソッド呼び出し内のリクエスト オブジェクトとレスポンス オブジェクトで行われた呼び出しを無視します (つまり、期待どおりに記録しません)。 (とにかく、このテストには関係ありません)。たとえば、私がテストしているサーブレット クラスのメソッドは次のようになります。HttpServletRequestHttpServletResponsedoPost()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()が無視されるように、どうすればやり直すことができますか?

4

5 に答える 5

2

Mockito http://mockito.org/を試してください。

EasyMock から使用する方がはるかに簡単で、すべてのメソッド呼び出しをコーディングする必要はありません。

于 2010-09-17T21:19:35.500 に答える
1

同様のシナリオでテストするための代替アプローチ:

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のメソッドを呼び出します。

于 2012-04-13T23:07:59.610 に答える
1

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 をご覧ください。

于 2011-06-07T17:04:53.033 に答える
1

録音をオフにするには、素敵なモックを使用します。ドキュメントから:

createMock()すべてのメソッドのデフォルトの動作によって返されるモック オブジェクトではAssertionError、すべての予期しないメソッド呼び出しに対して をスローします。デフォルトですべてのメソッド呼び出しを許可し、適切な空の値 (0、null、または false) を返す「適切な」モック オブジェクトが必要な場合は、createNiceMock()代わりに使用します。

また、より一般的には、モックしたいのはcreatePortletContext(servletRequest, servletResponse). 残念ながら、それは静的呼び出しです。このモックを実現するにはportletContext、 を返す独自のファクトリを作成し、このファクトリをテスト対象のクラス (できればコンストラクター内) に渡します。このファクトリとportletContextもモック化して、ここで重要なもの、つまり自分が書いたコードだけをテストできるようにします。

于 2012-04-18T12:28:26.097 に答える
1

おそらく、次のようなものが必要です。

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

または、Péter Török が提案するように createNiceMock() を使用します。

于 2010-09-17T21:34:05.933 に答える