web-dev-qa-db-ja.com

Jersey Client APIを呼び出すテストコードを単体テストするにはどうすればよいですか?

私はJerseyクライアントAPIを呼び出すコードを作成しました。このAPIは、自分の制御が及ばないWebサービスを呼び出します。ユニットテストで実際のWebサービスを呼び出さないようにします。

ジャージークライアントAPIを呼び出すコードの単体テストを作成するための最良のアプローチは何ですか?ジャージーサーバーAPIを使用してJAX-RSWebサービスを作成してから、単体テストにジャージーテストフレームワークを使用する必要がありますか?または、Jersey Webサービスの呼び出しをモックアウトする必要がありますか? JMockにアクセスできます。または、別のアプローチを試す必要がありますか?

調査中に、 このディスカッション さまざまなオプションについて説明していることがわかりましたが、完全な解決策を見つけました。提案されたJUnitアプローチを示す利用可能なコード例はありますか?ジャージーのドキュメントには何も見つかりませんでした。

関連するソースコードは次のとおりです。

public String getResult(URI uri) throws Exception {
  // error handling code removed for clarity
  ClientConfig clientConfig = new DefaultClientConfig();
  Client client = Client.create(clientConfig);
  WebResource service = client.resource(uri);
  String result = service.accept(accept).get(String.class);
  return result;
}

これが私が合格したいテストコードの例です。 (1)有効なURIを渡して有効な文字列を取得し、(2)無効な(何らかの理由で-到達不能または無許可の)URIを渡して例外を取得することをテストしたいと思います。

@Test
public void testGetResult_ValidUri() throws Exception {
  String xml = retriever.getResult(VALID_URI);
  Assert.assertFalse(StringUtils.isBlank(xml));
}

@Test(expected = IllegalArgumentException.class)
public void testGetResult_InvalidUri() throws Exception {
  retriever.getResult(INVALID_URI);
}

上記のすべては、私のコードが何をするかについての簡単な説明です。実際には、その上に2つのURIを受け入れるレイヤーがあり、最初に最初のURIの呼び出しを試み、そのURIが失敗した場合、2番目のURIの呼び出しを試みます。 (1)最初のURIが成功する、(2)最初のURIが失敗し、2番目のURIが成功する、(3)両方のURIが失敗するユニットテストが必要です。このコードは十分に複雑なので、JUnitを使用してこれらのさまざまなシナリオをテストしたいのですが、これを行うには、実際のスタンドインWebサービスを実行するか、JerseyクライアントAPI呼び出しをモックアウトする必要があります。

26
BennyMcBenBen

サービスコールのモックには、MockitoまたはEasymockを使用してみてください。実際に使用されているこれらのメソッドのみをモックする必要があります。すべてのメソッドをモックする必要はありません。 WebResourceクラスのモックオブジェクトを作成してから、メソッド呼び出しをモックで受け入れることができます。

@ BeforeClass/@ Before JUnitテストメソッドに次のように記述します(Mockitoの例)

WebResource res = mock(WebResource.class);
when(res.accept(something)).thenReturn(thatWhatYouWant);

次に、テストでresオブジェクトを実際のオブジェクトであるかのように使用し、その上でモックメソッドを呼び出すことができます。値を返す代わりに、例外をスローすることもできます。 Mockito かなりかっこいいです。

15

通常、あなたが本当に求めているのは "私がJerseyClient DSLを使用する方法は、正しいペイロードとURLパラメーターを使用して正しいURLへの要求を生成します" 。 Mockitoでこれをテストすることは非常に冗長であり、セットアップコードは通常次のようになります。

    when(authentication.queryParam(eq("sa"), anyBoolean())).thenReturn(testAuthentication);
    when(testAuthentication.resolveTemplate("channel", "smf")).thenReturn(testAuthentication);
    when(testAuthentication.request(
            MediaType.APPLICATION_JSON_TYPE)).thenReturn(mockRequestBuilder);
    when(mockRequestBuilder.post(any(Entity.class))).thenReturn(mockResponse);
    when(mockResponse.readEntity(ResponseWrapper.class)).thenReturn(successfulAuthResponse());

そして、これは基本的に単一のRESTリクエストの場合です。過度に冗長であり、期待される結果をテストする代わりに、Jersey ClientDSLを使用する際に正しいと思われる手順を複製するだけです。

上記の代わりに、簡単なサービスをモックすることを目指します。これには、Jettyサーバーを起動する WireMock を使用しました。ここで、 "のようなものをスタブできます。このURLへのリクエストを期待し、このメッセージで応答して、ペイロードはthis "です。

これは統合テストの端にあり、Mockitoを使用するよりも少し遅いことはわかっていますが、実際の結果をテストすることを重視しており、この場合はテストの可読性を重視しています。

WireMockベースのJerseyClientテストのセットアップは次のようになります。

@Test
public void exactUrlOnly() {
    stubFor(get(urlEqualTo("/some/thing"))
            .willReturn(aResponse()
                .withHeader("Content-Type", "text/plain")
                .withBody("Hello world!")));

   assertThat(testClient.get("/some/thing").statusCode(), is(200));
   assertThat(testClient.get("/some/thing/else").statusCode(), is(404));
}
13
vertti

似たようなサービスを実装し、単体テストのセットアップでHttpServerFactoryを使用してサービスを開始するだけです。

0
Chase