1. 概要

このチュートリアルでは、ライブ統合テスト(JSONペイロードを使用)を使用してRESTAPIをテストする基本的な原則と仕組みに焦点を当てています。

主な目標は、APIの基本的な正確さをテストするための概要を提供することです。例として、最新バージョンの GitHub RESTAPIを使用します。

内部アプリケーションの場合、この種のテストは通常、継続的インテグレーションプロセスの後期ステップとして実行され、RESTAPIが既にデプロイされた後に使用されます。

RESTリソースをテストする場合、通常、テストが焦点を当てるべき直交する責任がいくつかあります。

  • HTTP応答コード
  • 応答内の他のHTTPヘッダー
  • ペイロード(JSON、XML)

各テストは単一の責任にのみ焦点を当て、単一のアサーションを含める必要があります。明確な分離に焦点を当てることには常に利点がありますが、この種のブラックボックステストを行う場合は、一般的な傾向としてさらに重要です。最初に複雑なテストシナリオを作成します。

統合テストのもう1つの重要な側面は、単一レベルの抽象化原則の順守です。テスト内のロジックは高レベルで作成する必要があります。 リクエストの作成、サーバーへのHTTPリクエストの送信、IOの処理などの詳細は、インラインではなく、ユーティリティメソッドを介して実行する必要があります。

2. ステータスコードのテスト

@Test
public void givenUserDoesNotExists_whenUserInfoIsRetrieved_then404IsReceived()
  throws ClientProtocolException, IOException {
 
    // Given
    String name = RandomStringUtils.randomAlphabetic( 8 );
    HttpUriRequest request = new HttpGet( "https://api.github.com/users/" + name );

    // When
    HttpResponse httpResponse = HttpClientBuilder.create().build().execute( request );

    // Then
    assertThat(
      httpResponse.getStatusLine().getStatusCode(),
      equalTo(HttpStatus.SC_NOT_FOUND));
}

これはかなり単純なテストです。テストスイートにあまり複雑さを加えることなく、基本的なハッピーパスが機能していることを確認します

何らかの理由で失敗した場合は、これが修正されるまで、このURLの他のテストを調べる必要はありません。

3. メディアタイプのテスト

@Test
public void 
givenRequestWithNoAcceptHeader_whenRequestIsExecuted_thenDefaultResponseContentTypeIsJson()
  throws ClientProtocolException, IOException {
 
   // Given
   String jsonMimeType = "application/json";
   HttpUriRequest request = new HttpGet( "https://api.github.com/users/eugenp" );

   // When
   HttpResponse response = HttpClientBuilder.create().build().execute( request );

   // Then
   String mimeType = ContentType.getOrDefault(response.getEntity()).getMimeType();
   assertEquals( jsonMimeType, mimeType );
}

これにより、応答に実際にJSONデータが含まれるようになります。

お気づきかもしれませんが、テストの論理的な進行を追跡しています –最初に応答ステータスコード(要求がOKであることを確認するため)、次に応答のメディアタイプ、そして次のテストでは、実際のJSONペイロードを確認します。

4. JSONペイロードのテスト

@Test
public void 
  givenUserExists_whenUserInformationIsRetrieved_thenRetrievedResourceIsCorrect()
  throws ClientProtocolException, IOException {
 
    // Given
    HttpUriRequest request = new HttpGet( "https://api.github.com/users/eugenp" );

    // When
    HttpResponse response = HttpClientBuilder.create().build().execute( request );

    // Then
    GitHubUser resource = RetrieveUtil.retrieveResourceFromResponse(
      response, GitHubUser.class);
    assertThat( "eugenp", Matchers.is( resource.getLogin() ) );
}

この場合、GitHubリソースのデフォルトの表現はJSONであることがわかっていますが、通常、 <code>応答のContent-Typeヘッダーは、リクエストの Accept ヘッダーと一緒にテストする必要があります。クライアントは、Acceptを介して特定のタイプの表現を要求します。サーバーは尊重する必要があります。

5. テスト用ユーティリティ

Jackson 2を使用して、生のJSON文字列をタイプセーフなJavaエンティティにマーシャリング解除します。

public class GitHubUser {

    private String login;

    // standard getters and setters
}

テストをクリーンで読みやすく、高レベルの抽象化に保つために、単純なユーティリティのみを使用しています。

public static <T> T retrieveResourceFromResponse(HttpResponse response, Class<T> clazz) 
  throws IOException {
 
    String jsonFromResponse = EntityUtils.toString(response.getEntity());
    ObjectMapper mapper = new ObjectMapper()
      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    return mapper.readValue(jsonFromResponse, clazz);
}

Jacksonは、GitHub APIが送信している不明なプロパティを無視していることに注意してください。これは、GitHubでのユーザーリソースの表現が非常に複雑になるためです。ここでは、その情報は必要ありません。

6. 依存関係

ユーティリティとテストは、次のライブラリを利用します。これらはすべてMavenCentralで利用できます。

7. 結論

これは、完全な統合テストスイートのあり方の一部にすぎません。 テストは、 REST API の基本的な正確さを保証することに焦点を当てており、より複雑なシナリオに入る必要はありません。

たとえば、次のものはカバーされていません:APIの検出可能性、同じリソースの異なる表現の消費など。

これらすべての例とコードスニペットの実装は、Githubにあります。これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。