知識庫 / Spring / Spring Boot RSS 訂閱

Spring Boot 與 WireMock 集成

Spring Boot,Testing
HongKong
4
10:47 AM · Dec 06 ,2025

1. 簡介

測試外部依賴項,如 REST API,在 Web 應用程序開發中可能具有挑戰性。網絡調用速度慢且不可靠,因為第三方服務可能不可用或返回意外數據。我們必須找到一種穩健的方法來模擬外部服務,以確保一致且可靠的應用程序測試。這時,WireMock 就派上用場了。

WireMock 是一個強大的 HTTP 模擬服務器,它允許我們對 HTTP 請求進行樁和驗證。 它提供了一個受控的測試環境,確保我們的集成測試快速、可重複且獨立於外部系統。

在本教程中,我們將探索如何將 WireMock 集成到 Spring Boot 項目中,並使用它編寫全面的測試。

2. Maven 依賴

為了使用 WireMock 與 Spring Boot 配合使用,我們需要在我們的 pom.xml 中包含 wiremock-spring-boot 依賴。

<dependency>
    <groupId>org.wiremock.integrations</groupId>
    <artifactId>wiremock-spring-boot</artifactId>
    <version>3.9.0</version>
    <scope>test</scope>
</dependency>

該依賴項提供 WireMock 與 Spring Boot 測試框架之間的無縫集成。

3. 編寫基本 WireMock 測試

在處理更復雜的場景之前,我們首先編寫一個簡單的 WireMock 測試。我們需要確保我們的 Spring Boot 應用程序能夠正確地與外部 API 交互。通過使用 @SpringBootTest@EnableWireMock 註解,WireMock 已在我們的測試環境中啓用。然後,我們可以定義一個簡單的測試用例來驗證 API 的行為:

@SpringBootTest(classes = SimpleWiremockTest.AppConfiguration.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableWireMock
class SimpleWiremockTest {
    @Value("${wiremock.server.baseUrl}")
    private String wireMockUrl;

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void givenWireMockStub_whenGetPing_thenReturnsPong() {
        stubFor(get("/ping").willReturn(ok("pong")));

        ResponseEntity<String> response = restTemplate.getForEntity(wireMockUrl + "/ping", String.class);

        Assertions.assertEquals("pong", response.getBody());
    }

    @SpringBootApplication
    static class AppConfiguration {}
}

在本次測試中,我們使用 註解啓動嵌入式 WireMock 服務器,用於測試環境。 註解從屬性文件中檢索 WireMock 的基本 URL。測試方法 stub 一個 /ping 端點,返回帶有 HTTP 200 狀態碼的 “pong”。然後,我們使用 TestRestTemplate 發送實際的 HTTP 請求,並驗證響應體與預期值匹配。這確保我們的應用程序正確地與模擬的外部服務進行通信。

4. 增加測試複雜度

現在我們已經有一個基本的測試用例,接下來我們將擴展我們的示例,模擬一個返回 JSON 響應並處理各種狀態碼的 REST API。這將幫助我們驗證應用程序如何處理不同的 API 行為。

4.1. 使用 Wiremock 模擬 JSON 響應

在 REST API 中,返回結構化的 JSON 響應是很常見的。我們也可以使用 Wiremock 樁來模擬這種情況:

@Test
void givenWireMockStub_whenGetGreeting_thenReturnsMockedJsonResponse() {
    String mockResponse = "{\"message\": \"Hello, Baeldung!\"}";
    stubFor(get("/api/greeting")
      .willReturn(okJson(mockResponse)));

    ResponseEntity<String> response = restTemplate.getForEntity(wireMockUrl + "/api/greeting", String.class);

    Assertions.assertEquals(HttpStatus.OK, response.getStatusCode());
    Assertions.assertEquals(mockResponse, response.getBody());
}

在本測試中,我們模擬一個 GET 請求到 /api/greeting,該請求返回一個包含問候消息的 JSON 響應。然後,我們要求 WireMock 服務器驗證響應狀態碼是否為 200 OK,以及響應體是否與預期的 JSON 結構相匹配。

4.2. 模擬錯誤響應

我們都知道,在網絡開發中,事情並不總是按預期進行,並且某些外部調用可能會返回錯誤。為了做好準備,我們可以模擬錯誤消息,使我們的應用程序能夠以適當的方式響應這些錯誤:

@Test
void givenWireMockStub_whenGetUnknownResource_thenReturnsNotFound() {
    stubFor(get("/api/unknown").willReturn(aResponse().withStatus(404)));

    ResponseEntity<String> response = restTemplate.getForEntity(wireMockUrl + "/api/unknown", String.class);

    Assertions.assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
}

5. 注入 WireMock 服務器

在更復雜的場景中,我們可能需要管理多個 WireMock 實例或使用特定設置對其進行配置。 WireMock 允許我們使用 標註,注入和配置多個 WireMock 服務器。 這種方法尤其適用於我們的應用程序與大量的外部服務交互,並且我們希望獨立地模擬每個服務。

<h3><strong>5.1. 注入單個 WireMock 服務器</strong></h3>
<p>首先,讓我們將一個 WireMock 服務器注入到我們的測試類中。當需要模擬單個外部服務時,此方法非常有用:</p>
@SpringBootTest(classes = SimpleWiremockTest.AppConfiguration.class,
  webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableWireMock({
    @ConfigureWireMock(name = "user-service", port = 8081),
})
public class InjectedWiremockTest {
    @InjectWireMock("user-service")
    WireMockServer mockUserService;

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void givenEmptyUserList_whenFetchingUsers_thenReturnsEmptyList() {
        mockUserService.stubFor(get("/users").willReturn(okJson("[]")));

        ResponseEntity<String> response = restTemplate.getForEntity(
          "http://localhost:8081/users",
          String.class);

        Assertions.assertEquals(HttpStatus.OK, response.getStatusCode());
        Assertions.assertEquals("[]", response.getBody());
    }
}

與之前的方法不同,通過使用 @EnableWireMock 並在測試類級別啓用 WireMock,無需顯式注入,這種方法允許更精細的控制,通過注入一個命名的 WireMock 服務器實例。 @ConfigureWireMock 註解明確定義了 WireMock 實例的名稱和端口,從而方便在不同的測試用例中管理多個外部服務。

@InjectWireMock(“user-service”) 允許我們直接訪問 WireMockServer 實例,並在測試方法中動態配置和管理其行為。

5.2. 使用多個 WireMock 服務器

在我們的應用程序與多個外部服務交互時,我們可能需要使用多個 WireMock 實例來模擬多個 API。WireMock 允許我們為每個實例配置和指定不同的名稱和端口:

@SpringBootTest(classes = SimpleWiremockTest.AppConfiguration.class,
  webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableWireMock({
    @ConfigureWireMock(name = "user-service", port = 8081),
    @ConfigureWireMock(name = "product-service", port = 8082)
})
public class InjectedWiremockTest {
    @InjectWireMock("user-service")
    WireMockServer mockUserService;

    @InjectWireMock("product-service")
    WireMockServer mockProductService;

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    void givenUserAndProductLists_whenFetchingUsersAndProducts_thenReturnsMockedData() {
        mockUserService.stubFor(get("/users")
          .willReturn(okJson("[{\"id\": 1, \"name\": \"John\"}]")));
        mockProductService.stubFor(get("/products")
          .willReturn(okJson("[{\"id\": 101, \"name\": \"Laptop\"}]")));

        ResponseEntity<String> userResponse = restTemplate
          .getForEntity("http://localhost:8081/users", String.class);
        ResponseEntity<String> productResponse = restTemplate
          .getForEntity("http://localhost:8082/products", String.class);

        Assertions.assertEquals(HttpStatus.OK, userResponse.getStatusCode());
        Assertions.assertEquals("[{\"id\": 1, \"name\": \"John\"}]", userResponse.getBody());

        Assertions.assertEquals(HttpStatus.OK, productResponse.getStatusCode());
        Assertions.assertEquals("[{\"id\": 101, \"name\": \"Laptop\"}]", productResponse.getBody());
    }
}

我們隔離了服務,確保對一個模擬服務器的更改不會干擾其他服務器。通過注入多個 WireMock 實例,我們可以完全模擬複雜的服務交互,從而使我們的測試更準確、更可靠。這種方法在微服務架構中尤其有益,因為不同的組件會與各種外部服務進行通信。

6. 結論

WireMock 是一款強大的工具,用於在 Spring Boot 應用程序中測試外部依賴項。 在本文中,我們創建了可靠、可重複且獨立的測試,而無需依賴實際的第三方服務。 我們從一個簡單的測試開始,並將其演變為更高級的場景,包括注入多個 WireMock 服務器。

通過這些技術,我們可以確保我們的應用程序正確處理外部 API 響應,無論它們返回預期數據或錯誤。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.