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 新增到您的測試應用程式內容中,它會在具有相同內容的方法和類別之間快取。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 會在每個測試類別之後,以及選擇性地在每個測試方法之後(由 wiremock.reset-mappings-after-each-test 屬性保護)重設對應(包括從 stubs 位置新增的對應)。

如果您使用 Spring Cloud Contract 的預設 Stub JAR,您的 Stub 會儲存在 /META-INF/group-id/artifact-id/versions/mappings/ 資料夾中。如果您想要從所有嵌入式 JAR 註冊該位置的所有 Stub,您可以使用以下語法

@AutoConfigureWireMock(port = 0, stubs = "classpath*:/META-INF...

使用檔案來指定 Stub 主體

WireMock 可以從類別路徑或檔案系統上的檔案讀取回應主體。在檔案系統的情況下,您可以在 JSON DSL 中看到回應具有 bodyFileName 而不是(字面)body。這些檔案會相對於根目錄(預設情況下為 src/test/resources/__files)解析。若要自訂此位置,您可以在 @AutoConfigureWireMock 註解中將 files 屬性設定為父目錄的位置(換句話說,__files 是一個子目錄)。您可以使用 Spring 資源表示法來參考 file:…​classpath:…​ 位置。不支援通用 URL。可以給定值清單 — 在這種情況下,WireMock 會在需要尋找回應主體時解析第一個存在的檔案。

當您組態 files 根目錄時,它也會影響 Stub 的自動載入,因為它們來自名為 mappings 的子目錄中的根位置。
files 的值對從 stubs 屬性明確載入的 Stub 沒有影響。

替代方案:使用 JUnit 規則

為了獲得更傳統的 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,因為建置器會透過回呼傳遞以初始化它,因此可以在該點在用戶端中設定 SSL 驗證。如果您使用 @AutoConfigureWireMock 註解或 Stub Runner,這會在您的測試中自動發生。如果您使用 JUnit @Rule 方法,您也需要新增 @AutoConfigureHttpClient 註解,如下列範例所示

@RunWith(SpringRunner.class)
@SpringBootTest("app.baseUrl=https://localhost: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 Mock

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 容器(如果有的話)。