为什么你一直在写假的测试用例?

2023-03-07 16:23:33 浏览数 (1)

原文链接:https://www.baeldung.com/integration-testing-a-rest-api

作者: Eugen Paraschiv

译者: helloworldtang

目录

  • 1. 概览
  • 2. 测试状态码
  • 3. 测试媒体类型
  • 4. 测试接口返回的JSON
  • 5. 测试利器
  • 6. 依赖
  • 7. 总结

1. 概览

本教程重点介绍使用自动化IT(集成测试)测试REST API的基本原则和机制。

我们的主要目标是介绍如何测试API的可用性——示例将使用最新版本的 GitHub REST API。 对于内部应用程序,此类测试通常在部署REST API之后,作为持续集成的后期步骤运行。

在测试REST资源时,通常会有一些正交的职责需要关注:

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

每个测试用例应该关注单个职责,并包含一个断言。清晰的关注点分离总是有好处的,并且在这种黑盒测试中就更重要了,因为通常的情况是在一开始就编写复杂的测试用例。

集成测试的另一个重要原则是坚持单一抽象层级——业务逻辑应该在更高层级的用例中完成。诸如创建请求、向服务器发送HTTP请求、处理IO等细节应该委托给第三方库,而不是自己实现并且到处散落在测试用例中。

2. 测试状态码

代码语言:javascript复制
@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));
}

这是一个相当简单的测试——它用来检查一个API是否是可用的,并不会给测试用例增加太多的复杂性。

不管出于什么原因它失败了,那么在被修复之前,我们就不需要查看这个API相关的测试用例。

3. 测试媒体类型

代码语言:javascript复制
@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。

正如您可能已经注意到的,我们在按照一个循序渐进的方式进行测试 ——首先是响应状态码(确保接口是可用的),然后是服务器响应的媒体类型,并且只有到下一个测试用例,我们才会检查接口返回的JSON数据。

4. 测试接口返回的JSON

代码语言:javascript复制
@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,但在通常情况下,响应的Content-Type头应该与请求的Accept头一起测试——客户端通过Accept请求资源特定类型的表述,这是服务器应该遵守的。

5. 测试利器

我们将使用Jackson 2将JSON字符串反序列化成一个类型安全的Java实体:

代码语言:javascript复制
public class GitHubUser {

    private String login;

    // standard getters and setters
}

我们只使用一个简单的工具来保持测试用例的整洁、可读性和一个比较高的抽象层级:

代码语言:javascript复制
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. 依赖

测试工具和测试用例使用的库在Maven Central上都是可用的,如下所示:

  • HttpClient
  • Jackson 2
  • Hamcrest (可选的)

7. 总结

上面的示例只是完整集成测试的一部分。测试着重于确保REST API的正确性,而不必涉及更复杂的情况,譬如,以下内容都没有涉及:API的可发现性、对同一资源使用不同的表述等等。

所有这些示例和代码片段都可以在Github上找到——这是一个基于maven的项目,因此应该很容易导入和运行。

0 人点赞