目的是对技术进行介绍,并为基本正确性编写一些测试。 这些示例将使用最新版本的GitHub REST API。

对于内部应用程序,这种测试通常将在持续集成过程中作为后期步骤运行,并在已部署REST API后使用它。

在测试REST资源时,通常应承担一些正交的职责,测试应重点关注:

  • HTTP 响应代码
  • 响应中的其他HTTP 标头
  • 有效负载 (JSON,XML)

每个测试应仅关注单个职责并包括单个声明。 专注于清晰的分离总是有好处的,但是当进行这种黑盒测试时,它就显得尤为重要,因为通常的趋势是在一开始就编写复杂的测试方案。

集成测试的另一个重要方面是遵守单一抽象原理–测试中的逻辑应以较高的层次编写。 诸如创建请求,将HTTP请求发送到服务器,处理IO等之类的细节不应内联而是通过实用程序方法来完成。

测试HTTP响应代码

@Test
public void givenUserDoesNotExists_whenUserInfoIsRetrieved_then404IsReceived()
      throws ClientProtocolException, IOException{
   // Given
   String name = randomAlphabetic( 8 );
   HttpUriRequest request = new HttpGet( "https://api.github.com/users/" + name );
   
   // When
   HttpResponse httpResponse = httpClient.execute( request );
   
   // Then
   RestAssert.assertResponseCodeIs( httpResponse, 404 );
}

这是一个相当简单的测试,它验证基本的快乐路径在起作用,而不会增加测试套件的复杂性。 如果由于某种原因它失败了,那么在此URL修复之前,无需检查该URL的任何其他测试。 由于验证响应代码是集成测试套件中最常见的断言之一,因此将使用自定义断言 。

public static void assertResponseCodeIs
      ( final HttpResponse response, final int expectedCode ){
   final int statusCode = httpResponse.getStatusLine().getStatusCode();
   assertEquals( expectedCode, statusCode );
}

测试HTTP响应的其他标头

@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 = this.httpClient.execute( request );
   
   // Then
   String mimeType = EntityUtils.getContentMimeType( response.getEntity() );
   assertEquals( jsonMimeType, mimeType );
}

这样可以确保在请求用户详细信息时的响应实际上是JSON。 被测试功能有一个逻辑上的进展-首先是响应代码,以确保请求正常,然后是请求的mime类型,然后才是对实际JSON是否正确的验证。

测试HTTP响应的JSON有效负载

@Test
public void givenUserExists_whenUserInformationIsRetrieved_thenRetrievedResourceIsCorrect()
      throws ClientProtocolException, IOException{
   // Given
   HttpUriRequest request = new HttpGet( "https://api.github.com/users/eugenp" );
   
   // When
   HttpResponse response = new DefaultHttpClient().execute( request );
   
   // Then
   GitHubUser resource =
      RetrieveUtil.retrieveResourceFromResponse( response, GitHubUser.class );
   assertThat( "eugenp", Matchers.is( resource.getLogin() ) );
}

在这种情况下,我知道GitHub资源的默认表示形式是JSON,但通常应将响应的Content-Type标头与请求的Accept标头一起进行测试-客户端通过Accept请求特定的表示类型,服务器应该兑现。

测试工具

以下是使测试保持较高抽象水平的实用程序:

–使用JSON有效负载(或直接使用POJO)装饰HTTP请求:

public static < T >HttpEntityEnclosingRequest decorateRequestWithResource
      ( final HttpEntityEnclosingRequest request, final T resource )
      throws IOException{
   Preconditions.checkNotNull( request );
   Preconditions.checkNotNull( resource );
   
   final String resourceAsJson = JsonUtil.convertResourceToJson( resource );
   return JsonUtil.decorateRequestWithJson( request, resourceAsJson );
}

public static HttpEntityEnclosingRequest decorateRequestWithJson
      ( final HttpEntityEnclosingRequest request, final String json )
      throws UnsupportedEncodingException{
   Preconditions.checkNotNull( request );
   Preconditions.checkNotNull( json );
   
   request.setHeader( HttpConstants.CONTENT_TYPE_HEADER, "application/json" );
   request.setEntity( new StringEntity( json ) );
   
   return request;
}

–从HTTP响应中检索JSON有效负载(或直接获取POJO):

public static String retrieveJsonFromResponse( final HttpResponse response )
      throws IOException{
   Preconditions.checkNotNull( response );
   
   return IOUtils.toString( response.getEntity().getContent() );
}

public static < T >T retrieveResourceFromResponse
      ( final HttpResponse response, final Class< T > clazz ) throws IOException{
   Preconditions.checkNotNull( response );
   Preconditions.checkNotNull( clazz );
   
   final String jsonFromResponse = retrieveJsonFromResponse( response );
   return ConvertUtil.convertJsonToResource( jsonFromResponse, clazz );
}

–从Java对象(POJO)到JSON的转换实用程序:

public static < T >String convertResourceToJson( final T resource )
      throws IOException{
   Preconditions.checkNotNull( resource );
  
  return new ObjectMapper().writeValueAsString( resource );
}

public static < T >T convertJsonToResource
      ( final String json, final Class< T > clazzOfResource ) throws IOException{
  Preconditions.checkNotNull( json );
  Preconditions.checkNotNull( clazzOfResource );
  
  return new ObjectMapper().readValue( json, clazzOfResource );
}

依存关系

这些实用程序和测试利用了以下库,所有这些库都可以在Maven Central中使用:

结论

这只是完整的集成测试套件应有的一部分。 这些测试着重于确保REST API的基本正确性,而不涉及更复杂的场景,API的可发现性,对同一资源或其他更高级区域使用不同表示形式的情况。 我将在进一步的文章中讨论这些问题,同时在github上检出整个项目

参考:我们的JCG合作伙伴 Eugen Paraschiv在baeldung博客上 介绍了RESTful API的Java集成测试




翻译自: https://www.javacodegeeks.com/2011/10/java-restful-api-integration-testing.html