Spring Cloud Contract WireMock
Spring Cloud Contract WireMock 模組允許您在 Spring Boot 應用程式中使用 WireMock。有關更多詳細資訊,請檢視 Spring Cloud Contract 倉庫中的 samples 子資料夾。
如果您的 Spring Boot 應用程式使用 Tomcat 作為嵌入式伺服器(這是 spring-boot-starter-web
的預設設定),您可以將 spring-cloud-starter-contract-stub-runner
新增到類路徑,並在測試中使用 @AutoConfigureWireMock
來使用 Wiremock。Wiremock 作為 Stub 伺服器執行,您可以使用 Java API 或在測試中透過靜態 JSON 宣告來註冊 Stub 行為。
要啟動 Stub 伺服器並監聽不同的埠,請使用(例如)@AutoConfigureWireMock(port=9999)
。對於隨機埠,請使用值 0
。Stub 伺服器埠可以使用 wiremock.server.port
屬性繫結到測試應用程式上下文。使用 @AutoConfigureWireMock
會向您的測試應用程式上下文新增一個型別為 WiremockConfiguration
的 Bean,該 Bean 在具有相同上下文的方法和類之間快取。Spring 整合測試也是如此。此外,您可以將型別為 WireMockServer
的 Bean 注入到測試中。註冊的 WireMock 伺服器在每個測試類後重置。但是,如果需要在每個測試方法後重置它,請將 wiremock.reset-mappings-after-each-test
屬性設定為 true
。
自動註冊 Stub
如果您使用 @AutoConfigureWireMock
,它會從檔案系統或類路徑(預設從 file:src/test/resources/mappings
)註冊 WireMock JSON Stub。您可以透過使用註解中的 stubs
屬性來自定義位置,該屬性可以是 Ant 風格的資源模式或目錄。如果是目錄,則附加 */.json
。以下程式碼顯示了一個示例
@RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureWireMock(stubs="classpath:/stubs") public class WiremockImportApplicationTests { @Autowired private Service service; @Test public void contextLoads() throws Exception { assertThat(this.service.go()).isEqualTo("Hello World!"); } }
實際上,WireMock 總是從 src/test/resources/mappings *以及* stubs 屬性中的自定義位置載入對映。要更改此行為,您還可以指定檔案根目錄,如本文件的下一節所述。 |
此外,stubs 位置中的對映不被視為 Wiremock “預設對映”的一部分,並且測試期間對 com.github.tomakehurst.wiremock.client.WireMock.resetToDefaultMappings 的呼叫不會導致包含 stubs 位置中的對映。但是,org.springframework.cloud.contract.wiremock.WireMockTestExecutionListener 會在每個測試類之後重置對映(包括新增來自 stubs 位置的對映),並且可以選擇在每個測試方法之後重置(由 wiremock.reset-mappings-after-each-test 屬性控制)。 |
如果您使用 Spring Cloud Contract 的預設 stub jar,您的 stub 將儲存在 /META-INF/group-id/artifact-id/versions/mappings/
資料夾中。如果您想註冊所有嵌入式 JAR 中來自該位置的所有 stub,可以使用以下語法
@AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF...
使用檔案指定 Stub Body
WireMock 可以從類路徑或檔案系統中的檔案讀取響應 Body。對於檔案系統,您可以在 JSON DSL 中看到響應有一個 bodyFileName
而不是(字面的)body
。檔案相對於根目錄解析(預設是 src/test/resources/__files
)。要自定義此位置,您可以將 @AutoConfigureWireMock
註解中的 files
屬性設定為父目錄的位置(換句話說,__files
是一個子目錄)。您可以使用 Spring 資源表示法引用 file:…
或 classpath:…
位置。不支援通用 URL。可以指定值列表——在這種情況下,WireMock 需要找到響應 Body 時將解析第一個存在的檔案。
配置 files 根目錄時,它也會影響 stub 的自動載入,因為它們來自根目錄中的一個名為 mappings 的子目錄。 |
files 的值對從 stubs 屬性明確載入的 stub 沒有影響。 |
備選方案:使用 JUnit Rule
對於更傳統的 WireMock 體驗,您可以使用 JUnit @Rules
啟動和停止伺服器。為此,請使用 WireMockSpring
便利類獲取一個 Options
例項,如下面的示例所示
@ClassRule
表示伺服器在此類中的所有方法執行後關閉。
Rest Template 的寬鬆 SSL 驗證
WireMock 允許您使用 https
URL 協議來 Stub 一個“安全”伺服器。如果您的應用程式在整合測試中想要聯絡該 Stub 伺服器,它會發現 SSL 證書無效(自安裝證書的常見問題)。最佳選擇通常是重新配置客戶端使用 http
。如果這不是一個選項,您可以讓 Spring 配置一個忽略 SSL 驗證錯誤的 HTTP 客戶端(當然,僅用於測試)。
為了最大限度地減少麻煩,您需要在應用程式中使用 Spring Boot 的 RestTemplateBuilder
,如下例所示
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
您需要 RestTemplateBuilder
,因為 Builder 會透過回撥傳遞進行初始化,這樣就可以在該點設定客戶端的 SSL 驗證。如果您使用 @AutoConfigureWireMock
註解或 Stub Runner,這在測試中會自動發生。如果您使用 JUnit @Rule
方法,您還需要新增 @AutoConfigureHttpClient
註解,如下例所示
@RunWith(SpringRunner.class)
@SpringBootTest("app.baseUrl=https://:6443")
@AutoConfigureHttpClient
public class WiremockHttpsServerApplicationTests {
@ClassRule
public static WireMockClassRule wiremock = new WireMockClassRule(
WireMockSpring.options().httpsPort(6443));
...
}
如果您使用 spring-boot-starter-test
,類路徑中會有 Apache HTTP 客戶端,並且它會被 RestTemplateBuilder
選中並配置為忽略 SSL 錯誤。如果您使用預設的 java.net
客戶端,則不需要該註解(但新增它也無害)。目前不支援其他客戶端,但可能會在未來版本中新增。
要停用自定義的 RestTemplateBuilder
,請將 wiremock.rest-template-ssl-enabled
屬性設定為 false
。
WireMock 和 Spring MVC Mocks
Spring Cloud Contract 提供了一個便利類,可以將 JSON WireMock Stub 載入到 Spring MockRestServiceServer
中。下面的專案展示了這一點。
baseUrl
值會新增到所有 Mock 呼叫之前,並且 stubs()
方法接受一個 stub 路徑資源模式作為引數。在上面的例子中,定義在 /stubs/resource.json
的 stub 被載入到 Mock 伺服器中。如果 RestTemplate
被要求訪問 example.org/
,它將獲得在該 URL 宣告的響應。可以指定多個 stub 模式,每個模式可以是一個目錄(用於遞迴列出所有 .json
檔案)、一個固定的檔名(如上例所示)或一個 Ant 風格的模式。JSON 格式是標準的 WireMock 格式,您可以在 WireMock 網站上閱讀有關資訊。
目前,Spring Cloud Contract Verifier 支援 Tomcat、Jetty 和 Undertow 作為 Spring Boot 嵌入式伺服器,而 Wiremock 本身對特定版本的 Jetty(當前為 9.2)有“原生”支援。要使用原生 Jetty,您需要新增原生 Wiremock 依賴並排除 Spring Boot 容器(如果存在)。