Test a REST API with Java – 用Java测试一个REST API

最后修改: 2011年 10月 13日


1. Overview


In this tutorial, we’ll focus on the basic principles and mechanics of testing a REST API with live Integration Tests (with a JSON payload).

在本教程中,我们将重点介绍用实时集成测试测试REST API的基本原则和机制(带JSON有效载荷)。

Our main goal is to provide an introduction to testing the basic correctness of the API, and we’ll use the latest version of the GitHub REST API for the examples.

更多我们的主要目标是提供有关测试 API 基本正确性的介绍,我们将使用最新版本的 GitHub REST API 进行示例。

For an internal application, this kind of testing will usually run as a late step in a Continuous Integration process, consuming the REST API after it’s already been deployed.

对于一个内部应用,这种测试通常作为持续集成过程的后期步骤运行,在它已经被部署后消耗REST API。

When testing a REST resource, there are usually a few orthogonal responsibilities the tests should focus on:


  • the HTTP response code
  • other HTTP headers in the response
  • the payload (JSON, XML)

Each test should only focus on a single responsibility and include a single assertion. Focusing on a clear separation always has benefits, but when doing this kind of black box testing, it’s even more important because the general tendency is to write complex test scenarios in the very beginning.


Another important aspect of integration tests is adherence to the Single Level of Abstraction Principle; we should write the logic within a test at a high level. Details such as creating the request, sending the HTTP request to the server, dealing with IO, etc., shouldn’t be done inline, but via utility methods.


2. Testing the Status Code


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

This is a rather simple test. It verifies that a basic happy path is working, without adding too much complexity to the test suite.


If, for whatever reason, it fails, then we don’t need to look at any other test for this URL until we fix it.


3. Testing the Media Type


public void 
  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 );

This ensures that the Response actually contains JSON data.


As we can see, we’re following a logical progression of tests. First is the Response Status Code (to ensure the request was OK), and then the Media Type of the Response. Only in the next test will we look at the actual JSON payload.


4. Testing the JSON Payload


public void 
  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() ) );

In this case, the default representation of the GitHub resources is JSON, but usually, the Content-Type header of the response should be tested alongside the Accept header of the request. The client asks for a particular type of representation via Accept, which the server should honor.


5. Utilities for Testing


We’ll use Jackson 2 to unmarshall the raw JSON String into a type-safe Java Entity:

我们将使用Jackson 2将原始JSON字符串解构为一个类型安全的Java实体。

public class GitHubUser {

    private String login;

    // standard getters and setters

We’re only using a simple utility to keep the tests clean, readable, and at a high level of abstraction:


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);

Notice that Jackson is ignoring unknown properties that the GitHub API is sending our way. This is simply because the Representation of a User Resource on GitHub gets pretty complex, and we don’t need any of that information here.

请注意,Jackson正在忽略GitHub API发送给我们的未知属性。这只是因为GitHub上的用户资源表示法变得相当复杂,而我们在这里不需要任何这些信息。

6. Dependencies


The utilities and tests make use of the following libraries, all of which are available in Maven central:


7. Conclusion


This is only one part of what the complete integration testing suite should be. The tests focus on ensuring basic correctness for the REST API, without going into more complex scenarios.

这只是完整的集成测试套件应该有的一部分。测试的重点是确保REST API的基本正确性,而不是进入更复杂的场景。

For example, we didn’t cover the following: discoverability of the API, consumption of different representations for the same Resource, etc.


The implementation of all of these examples and code snippets can be found over on Github. This is a Maven-based project, so it should be easy to import and run as it is.