1. 概述
本教程將重點介紹通過集成測試,測試 REST API 的原理和機制。 具體來説,我們將使用實時請求和 JSON 負載對 API 進行測試,以確保其正確性和行為。
2. API 集成測試
API 集成測試涉及測試我們的應用程序與其外部依賴項(如數據庫、第三方服務或其它 API)之間的交互。 目標是確保系統不同組件協同工作,按預期運行。 與專注於單個組件的單元測試不同,集成測試通過向我們的 API 發送實際的 HTTP 請求並檢查響應,模擬真實世界的使用情況,從而確保一切都按預期工作。
2.1. API 集成測試的重要性
雖然單元測試確保單個代碼片段按照預期工作,但它們無法捕獲由於這些組件集成而產生的潛在問題。集成測試通過檢查系統不同部分之間的通信方式,從而解決這些問題,確保組件之間的誤解或錯誤不會影響整體功能。
此外,它們還能讓團隊對系統在生產環境中按預期運行充滿信心,從而降低部署後出現故障的風險。
2.2. 進行API集成測試的時間點
通常,API集成測試在單元測試之後,但在發佈之前進行。單元測試確認了單個組件的功能是否正常,集成測試則確保這些組件能夠協同工作,如預期。
集成測試也應在發佈前進行,以捕獲任何可能出現的迴歸問題或集成問題,這些問題可能與新功能或更新有關。
3. 測試狀態碼
為了確保API在用户不存在時按預期行為,我們可以測試響應狀態碼:
@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));
}這是一個相當簡單的測試。它驗證了一條基本的成功路徑是否正常工作,而沒有為測試套件添加過多的複雜性。
如果,無論出於何原因,它失敗了,那麼我們不需要查看任何其他測試,直到我們修復它。
4. 測試媒體類型
我們還可以測試媒體類型,以確保響應的默認 Content-Type 是 JSON。
@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 負載。
5. 測試 JSON 負載
為了驗證 API 是否返回正確的數據,我們可以測試 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,但通常應同時測試響應的Content-Type 頭部和請求的Accept 頭部。客户端通過Accept頭部請求特定類型的表示形式,服務器應尊重此請求。
6. 測試工具
我們將使用 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 上 User 資源的表示非常複雜,我們這裏不需要這些信息。
7. 依賴項
這些實用工具和測試依賴於以下庫,所有庫均可在 Maven Central 上找到:
- HttpClient
- Jackson 2
- Hamcrest (可選)
8. 結論
這只是完整的集成測試套件的一部分。這些測試旨在確保 REST API 的基本正確性,而沒有深入到更復雜的場景。
例如,我們沒有涵蓋以下內容:API 的可發現性、相同資源的各種表示形式的消費等。