wiremock 使用_使用WireMock进行更好的集成测试
wiremock 使用
無論您是遵循傳統的測試金字塔還是采用諸如“ 測試蜂窩”這樣的較新方法,都應該在開發過程中的某個時候開始編寫集成測試。
您可以編寫多種類型的集成測試。 從持久性測試開始,您可以檢查組件之間的交互,也可以模擬調用外部服務。 本文將討論后一種情況。 在談論WireMock之前,讓我們從一個激勵性的例子開始。
ChuckNorrisFact服務
完整的示例可以在GitHub上找到 。
在以前的博客文章中,您可能已經看到我使用Chuck Norris事實API 。 該API將為我們提供實現所依賴的另一項服務的示例。 我們有一個簡單的ChuckNorrisFactController作為用于手動測試的API。 旁邊的“業務”類存在ChuckNorrisService ,做調用外部API。 它使用Spring的RestTemplate 。 沒什么特別的。 我多次看到的是模擬RestTemplate并返回一些預先確定的答案的測試。 該實現可能如下所示:
在檢查成功案例的常規單元測試旁邊,至少會有一個覆蓋錯誤案例的測試,即4xx或5xx狀態代碼:
@Test public void shouldReturnBackupFactInCaseOfError() { String url = " http://localhost:8080 " ; RestTemplate mockTemplate = mock(RestTemplate. class ); ResponseEntity<ChuckNorrisFactResponse> responseEntity = new ResponseEntity<>(HttpStatus.SERVICE_UNAVAILABLE); when(mockTemplate.getForEntity(url, ChuckNorrisFactResponse. class )).thenReturn(responseEntity); var service = new ChuckNorrisService(mockTemplate, url); ChuckNorrisFact retrieved = service.retrieveFact(); assertThat(retrieved).isEqualTo(ChuckNorrisService.BACKUP_FACT); } 看起來還不錯吧? 響應實體返回503錯誤代碼,我們的服務不會崩潰。 所有測試都是綠色的,我們可以部署我們的應用程序。
不幸的是,Spring的RestTemplate不能這樣工作。 getForEntity的方法簽名為我們提供了一個非常小的提示。 它指出throws RestClientException 。 這就是模擬的RestTemplate與實際實現不同的地方。 我們將永遠不會收到帶有4xx或5xx狀態代碼的ResponseEntity 。 RestTemplate將拋出一個子類 RestClientException 。 通過查看類的層次結構,我們可以對可能拋出的結果有一個很好的印象:
因此,讓我們看看如何使這個測試更好。
WireMock進行救援
WireMock通過啟動模擬服務器并返回將其配置為返回的答案來模擬Web服務。 得益于出色的DSL,它很容易集成到測試中,并且模擬請求也很簡單。
對于JUnit 4,有一個WireMockRule可以幫助啟動停止服務器。 對于JUnit 5,您必須自己做。 當您檢查示例項目時,您可以找到ChuckNorrisServiceIntegrationTest 。 這是基于JUnit 4的SpringBoot測試。讓我們來看一下。 最重要的部分是ClassRule :
如前所述,這將啟動和停止WireMock服務器。 您也可以使用常規Rule來為每個測試啟動和停止服務器。 對于我們的測試,這不是必需的。
接下來,您可以看到幾種configureWireMockFor...方法。 這些包含WireMock何時返回答案的說明。 將WireMock配置分為幾種方法并從測試中調用它們是我使用WireMock的方法。 當然,您可以在@Before方法中設置所有可能的請求。 對于成功案例,我們這樣做:
所有方法都是從com.github.tomakehurst.wiremock.client.WireMock靜態com.github.tomakehurst.wiremock.client.WireMock 。 如您所見,我們將HTTP GET存入路徑/jokes/random并返回JSON對象。 的
okJson()方法只是JSON內容的200個響應的簡寫。 對于錯誤情況,代碼甚至更簡單:
如您所見,DSL使閱讀說明變得容易。
將WireMock放置在適當的位置,我們可以看到我們先前的實現不起作用,因為RestTemplate引發了異常。 因此,我們必須調整代碼:
這已經涵蓋了WireMock的基本用例。 配置請求的答案,執行測試,檢查結果。 就這么簡單。
但是,在云環境中運行測試時,通常會遇到一個問題。 讓我們看看我們能做什么。
動態端口上的WireMock
您可能已經注意到,項目中的集成測試包含一個
ApplicationContextInitializer類及其@TestPropertySource批注將覆蓋實際API的URL。 那是因為我想在隨機端口上啟動WireMock。 當然,您可以為WireMock配置一個固定端口,并在測試中將此端口用作硬編碼值。 但是,如果您的測試在某些云提供商的基礎架構上運行,則無法確定端口是否可用。 因此,我認為隨機端口更好。
不過,在Spring應用程序中使用屬性時,我們必須以某種方式將隨機端口傳遞給我們的服務。 或者,如您在示例中看到的那樣,覆蓋URL。 這就是為什么我們使用ApplicationContextInitializer 。 我們將動態分配的端口添加到應用程序上下文中,然后可以使用屬性來引用它 ${wiremock.port} 。 這里唯一的缺點是我們現在必須使用ClassRule。 否則,我們無法在初始化Spring應用程序之前訪問端口。 解決了此問題后,讓我們看一下涉及HTTP調用的一個常見問題。
超時時間
WireMock提供了更多的響應可能性,而不僅僅是對GET請求的簡單答復。 經常被遺忘的另一個測試案例是測試超時。 開發人員往往會忘記在RestTemplate甚至URLConnections上設置超時。 如果沒有超時,則兩者都將等待無限量的時間進行響應。 在最好的情況下,您不會注意到,在最壞的情況下,所有線程都將等待永遠不會到達的響應。
因此,我們應該添加一個模擬超時的測試。 當然,我們也可以使用Mockito模擬來創建延遲,但是在這種情況下,我們將再次猜測RestTemplate的行為。 使用WireMock模擬延遲非常簡單:
withFixedDelay()需要一個表示毫秒的int值。 我更喜歡使用Duration或至少一個表示該參數表示毫秒的常量,而不必每次都讀取JavaDoc。
在RestTemplate上設置超時并添加響應緩慢的測試后,我們可以看到RestTemplate拋出ResourceAccessException 。 因此,我們可以調整catch塊以捕獲此異常和HttpStatusCodeException也可以僅捕獲兩者的超類:
現在,我們已經很好地介紹了執行HTTP請求時最常見的情況,并且可以確定我們正在測試接近真實條件的條件。
為什么不飛翔?
HTTP集成測試的另一個選擇是Hoverfly 。 它的工作方式類似于WireMock,但我更喜歡后者。 原因是在運行包含瀏覽器的端到端測試時,WireMock也非常有用。 Hoverfly(至少是Java庫)受JVM代理的限制。 這可能使它比WireMock更快,但是當例如某些JavaScript代碼開始起作用時,它根本不起作用。 當您的瀏覽器代碼也直接調用其他一些服務時,WireMock啟動Web服務器這一事實非常有用。 然后,您也可以使用WireMock來模擬它們,并編寫例如Selenium測試。
結論
我希望本文可以向您展示兩件事:
當然,這兩個主題都可以填滿更多文章。 盡管如此,我還是想讓您了解如何使用WireMock及其功能。 隨時檢查他們的文檔,然后嘗試更多其他事情。 例如,也可以使用WireMock測試身份驗證。
翻譯自: https://www.javacodegeeks.com/2019/11/better-integration-tests-with-wiremock.html
wiremock 使用
總結
以上是生活随笔為你收集整理的wiremock 使用_使用WireMock进行更好的集成测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spock测试_将Spock 1.3测试
- 下一篇: 节目用英语怎么说 节目用英语如何说