測試客戶端應用程式

您可以使用客戶端測試來測試內部使用 RestTemplate 的程式碼。核心思想是宣告預期的請求並提供“存根”響應,這樣您就可以專注於獨立測試程式碼(即無需執行伺服器)。以下示例展示瞭如何實現:

  • Java

  • Kotlin

RestTemplate restTemplate = new RestTemplate();

MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess());

// Test code that uses the above RestTemplate ...

mockServer.verify();
val restTemplate = RestTemplate()

val mockServer = MockRestServiceServer.bindTo(restTemplate).build()
mockServer.expect(requestTo("/greeting")).andRespond(withSuccess())

// Test code that uses the above RestTemplate ...

mockServer.verify()

在前面的示例中,MockRestServiceServer(客戶端 REST 測試的核心類)使用自定義的 ClientHttpRequestFactory 配置 RestTemplate,該工廠會針對期望斷言實際請求並返回“存根”響應。在本例中,我們期望一個對 /greeting 的請求,並希望返回一個帶有 text/plain 內容的 200 響應。我們可以根據需要定義額外的預期請求和存根響應。當我們定義了預期請求和存根響應後,RestTemplate 可以在客戶端程式碼中照常使用。測試結束時,可以使用 mockServer.verify() 來驗證所有期望是否都已滿足。

預設情況下,請求的順序與期望宣告的順序一致。您可以在構建伺服器時設定 ignoreExpectOrder 選項,在這種情況下,所有期望都會被檢查(按順序)以找到與給定請求匹配的那個。這意味著請求可以按任意順序到達。以下示例使用了 ignoreExpectOrder

  • Java

  • Kotlin

server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build();
server = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()

即使預設情況下請求是無序的,每個請求也只能執行一次。expect 方法提供了一個過載變體,它接受一個 ExpectedCount 引數,用於指定計數範圍(例如,oncemanyTimesmaxminbetween 等)。以下示例使用了 times

  • Java

  • Kotlin

RestTemplate restTemplate = new RestTemplate();

MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(times(2), requestTo("/something")).andRespond(withSuccess());
mockServer.expect(times(3), requestTo("/somewhere")).andRespond(withSuccess());

// ...

mockServer.verify();
val restTemplate = RestTemplate()

val mockServer = MockRestServiceServer.bindTo(restTemplate).build()
mockServer.expect(times(2), requestTo("/something")).andRespond(withSuccess())
mockServer.expect(times(3), requestTo("/somewhere")).andRespond(withSuccess())

// ...

mockServer.verify()

請注意,當 ignoreExpectOrder 未設定(預設值),並且請求期望按宣告順序進行時,該順序僅適用於任何預期請求的第一次出現。例如,如果期望 "/something" 出現兩次,然後期望 "/somewhere" 出現三次,那麼在 "/somewhere" 的請求出現之前,應該有一個對 "/something" 的請求,但除此之外,後續的 "/something" 和 "/somewhere" 請求可以在任何時候出現。

作為上述方法的替代方案,客戶端測試支援還提供了一個 ClientHttpRequestFactory 實現,您可以將其配置到 RestTemplate 中,以將其繫結到 MockMvc 例項。這允許使用實際的伺服器端邏輯處理請求,但無需執行伺服器。以下示例展示瞭如何實現:

  • Java

  • Kotlin

MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
this.restTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(mockMvc));

// Test code that uses the above RestTemplate ...
val mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build()
restTemplate = RestTemplate(MockMvcClientHttpRequestFactory(mockMvc))

// Test code that uses the above RestTemplate ...

在某些情況下,可能需要實際呼叫遠端服務而不是模擬響應。以下示例展示瞭如何透過 ExecutingResponseCreator 來實現:

  • Java

  • Kotlin

RestTemplate restTemplate = new RestTemplate();

// Create ExecutingResponseCreator with the original request factory
ExecutingResponseCreator withActualResponse = new ExecutingResponseCreator(restTemplate.getRequestFactory());

MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build();
mockServer.expect(requestTo("/profile")).andRespond(withSuccess());
mockServer.expect(requestTo("/quoteOfTheDay")).andRespond(withActualResponse);

// Test code that uses the above RestTemplate ...

mockServer.verify();
val restTemplate = RestTemplate()

// Create ExecutingResponseCreator with the original request factory
val withActualResponse = new ExecutingResponseCreator(restTemplate.getRequestFactory())

val mockServer = MockRestServiceServer.bindTo(restTemplate).build()
mockServer.expect(requestTo("/profile")).andRespond(withSuccess())
mockServer.expect(requestTo("/quoteOfTheDay")).andRespond(withActualResponse)

// Test code that uses the above RestTemplate ...

mockServer.verify()

在前面的示例中,我們在 MockRestServiceServer 用不同的工廠替換 RestTemplateClientHttpRequestFactory 之前,使用 RestTemplate 的工廠建立了 ExecutingResponseCreator。然後,我們定義了兩種響應型別的期望:

  • 對於 /profile 端點,返回一個存根 200 響應(不會執行實際請求)

  • 透過呼叫 /quoteOfTheDay 端點獲得的響應

在第二種情況下,請求透過先前捕獲的 ClientHttpRequestFactory 執行。根據 RestTemplate 最初的配置方式,這會生成一個響應,該響應可能來自實際的遠端伺服器。

靜態匯入

與伺服器端測試一樣,客戶端測試的流暢 API 需要一些靜態匯入。透過搜尋 MockRest* 很容易找到它們。Eclipse 使用者應將 MockRestRequestMatchers.*MockRestResponseCreators.* 新增到 Eclipse 偏好設定中 Java → Editor → Content Assist → Favorites 下的“favorite static members”(收藏夾靜態成員)。這允許在輸入靜態方法名稱的第一個字元後使用內容輔助。其他 IDE(如 IntelliJ)可能不需要任何額外的配置。請檢查對靜態成員程式碼補全的支援。

客戶端 REST 測試的更多示例

Spring MVC Test 自己的測試包含客戶端 REST 測試的示例