From 6201983929f506cbde393ac1cd6345e83577fe51 Mon Sep 17 00:00:00 2001 From: Tom Akehurst Date: Mon, 2 Dec 2024 19:33:47 +0000 Subject: [PATCH] Updated Spring Boot integration docs (#322) * Added a new doc page for the Spring Boot integration and tweaked the Spring solution page * Various tweaks to Spring boot URLs and links * Fixed missing closing brace in code sample * Updated Spring Boot integration version and fixed its variable name --- _config.yml | 1 + _data/doc-categories.yml | 7 +- _docs/index.html | 2 +- ...ing-boot.md => spring-boot-integration.md} | 43 +--- _docs/spring-boot.md | 237 ++++++++++++++++++ 5 files changed, 252 insertions(+), 38 deletions(-) rename _docs/solutions/{spring-boot.md => spring-boot-integration.md} (51%) create mode 100644 _docs/spring-boot.md diff --git a/_config.yml b/_config.yml index d4df884a..ffb14665 100644 --- a/_config.yml +++ b/_config.yml @@ -239,6 +239,7 @@ wiremock_baseline: 3.x pageEditPrefix: https://github.com/wiremock/wiremock.org/edit/main/ grpc_extension_version: 0.8.1 +spring_boot_integration_version: 3.3.0 community_slack: join_url: https://slack.wiremock.org/ diff --git a/_data/doc-categories.yml b/_data/doc-categories.yml index abbae640..7ba615de 100644 --- a/_data/doc-categories.yml +++ b/_data/doc-categories.yml @@ -22,7 +22,7 @@ java: pages: - junit-jupiter - junit-extensions - - spring-boot + - spring-boot-integration - java-usage - configuration - running-without-http-server @@ -64,6 +64,11 @@ protocols: - jwt - https +integrations: + title: Integrations + pages: + - spring-boot + configuration: title: Advanced use-cases pages: diff --git a/_docs/index.html b/_docs/index.html index 1314ee6a..93b89744 100644 --- a/_docs/index.html +++ b/_docs/index.html @@ -236,7 +236,7 @@

By technology

Python - + Spring Boot diff --git a/_docs/solutions/spring-boot.md b/_docs/solutions/spring-boot-integration.md similarity index 51% rename from _docs/solutions/spring-boot.md rename to _docs/solutions/spring-boot-integration.md index 1bde3b8c..97d6cf5a 100644 --- a/_docs/solutions/spring-boot.md +++ b/_docs/solutions/spring-boot-integration.md @@ -2,62 +2,33 @@ layout: solution title: "Using WireMock with Spring Boot" meta_title: Running WireMock with Spring Boot | WireMock -toc_rank: 116 description: The team behind Spring Cloud Contract have created a library to support running WireMock using the “ambient” HTTP server redirect_from: - "/docs/spring-boot.html" logo: /images/logos/technology/spring.svg +hide-disclaimer: true ---
Centralize and scale your API mocks with WireMock Cloud.
-
Centralize and scale your API mocks with WireMock Cloud.
- ## WireMock Spring Boot -[WireMock Spring Boot](https://github.com/wiremock/wiremock-spring-boot) -simplifies testing HTTP clients in Spring Boot & Junit 5 based integration tests. -It includes fully declarative WireMock setup, -supports multiple `WireMockServer` instances, -automatically sets Spring environment properties, -and does not pollute Spring application context with extra beans. - -Example: +WireMock's official Spring Boot integration library is the simplest way to configure Spring Boot, Junit 5 and WireMock to work together. -```java -@SpringBootTest -@EnableWireMock -class DefaultInstanceTest { - @Value("${wiremock.server.baseUrl}") - private String wiremockUrl; +It includes fully declarative WireMock setup, supports multiple `WireMockServer` instances, automatically sets Spring environment properties, +and does not pollute Spring application context with extra beans. - @Test - void returnsTodos() { - WireMock.stubFor(get("/ping") - .willReturn(aResponse() - .withStatus(200))); +See [WireMock Spring Boot Integration](/docs/spring-boot/) for details on installation and usage. - RestAssured - .when() - .get(this.wiremockUrl + "/ping") - .then() - .statusCode(200); - } -} -``` +You can contribute or log an issue in the [GitHub project](https://github.com/wiremock/wiremock-spring-boot). ## Spring Cloud Contract -The team behind Spring Cloud Contract have created a library to support running WireMock using the "ambient" HTTP server. -It also simplifies some aspects of configuration and eliminates some common issues that occur when running Spring Boot and WireMock together. +WireMock provides the mocking capabilities for the Spring Cloud Contract project (a consumer-driven contract testing tool). See [Spring Cloud Contract WireMock](https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/project-features.html#features-wiremock) for details. -The article [Faking OAuth2 Single Sign-on in Spring](https://engineering.pivotal.io/post/faking_oauth_sso/) -from Pivotal's blog shows how WireMock can be used to test Spring apps that use 3rd party OAuth2 login. - - ## Jetty version issues when running WireMock and Spring together. WireMock's main artifact is built on Jetty 11, largely so that Java 11 support can be maintained. However, many Spring applications depend on Jetty 12 and the presence of both on the classpath causes WireMock to fail with a `ClassNotFoundException` or `NoClassDefFoundError` for Servlet API classes thrown during startup. diff --git a/_docs/spring-boot.md b/_docs/spring-boot.md new file mode 100644 index 00000000..b125126b --- /dev/null +++ b/_docs/spring-boot.md @@ -0,0 +1,237 @@ +--- +layout: docs +title: "WireMock Spring Boot Integration" +meta_title: Using WireMock's Spring Boot + JUnit 5 integration | WireMock +description: Integrating WireMock, Spring Boot and JUnit 5 via the official integration library. +--- + +WireMock's Spring Boot integration provides a simple, declarative way to configure and run one or more WireMock instances their JUnit tests. + +## Installation + +Maven: +```xml + + org.wiremock.integrations + wiremock-spring-boot + {{ site.spring_boot_integration_version }} + +``` + +Gradle: +```groovy +implementation 'org.wiremock.integrations:wiremock-spring-boot:{{ site.spring_boot_integration_version }}' +``` + +## Basic usage + +The integration is enabled by adding the `@EnableWireMock` annotation to your test class. + +```java +@SpringBootTest(classes = ExamplesTests.AppConfiguration.class) +@EnableWireMock +class ExampleTests { + + @Value("${wiremock.server.baseUrl}") + private String wireMockUrl; + + @Test + void returns_a_ping() { + stubFor(get("/ping").willReturn(ok("pong"))); + + RestClient client = RestClient.create(); + String body = client.get() + .uri(wireMockUrl + "/ping") + .retrieve() + .body(String.class); + + assertThat(body, is("pong")); + } + + @SpringBootApplication + static class AppConfiguration {} +} +``` + +### Injected properties + +The example above will start a WireMock instance with a sensible set of defaults and set the following properties in the Spring context: + +- `wiremock.server.baseUrl` - Base URL of WireMock server. +- `wiremock.server.port` - HTTP port of WireMock server. + +These property names can be changed as follows: + +```java +@EnableWireMock( + @ConfigureWireMock( + baseUrlProperties = { "customUrl", "sameCustomUrl" }, + portProperties = "customPort" +)) +class CustomPropertiesTest { + + @Value("${customUrl}") + private String customUrl; + + @Value("${sameCustomUrl}") + private String sameCustomUrl; + + @Value("${customPort}") + private String customPort; + + // ... +} +``` + + +## Declarative configuration +A number of WireMock's common configuration values can be overridden via the `@ConfigureWireMock` annotation, which is used as follows: + +```java +@EnableWireMock({ + @ConfigureWireMock( + name = "my-mock", + port = 8888 +}) +``` + +This currently supports the following config items: + +* `port`: the HTTP port number. Defaults to 0 i.e. random. +* `httpsPort`: the HTTPS port number. Defaults to 0 i.e. random. +* `name`: the WireMock instance name. It is usually a good idea to set this when running multiple WireMock instances. Defaults to `wiremock`. +* `usePortFromPredefinedPropertyIfFound`: if true, take the port number from the Spring configuration. Defaults to false. +* `portProperties`: Overrides for the HTTP port property name. +* `httpsPortProperties`: Overrides for the HTTPS port property name. +* `baseUrlProperties`: Overrides for the HTTP base URL property name. +* `httpsBaseUrlProperties`: Overrides for the HTTPS base URL property name. +* `filesUnderClasspath`: Classpath root that will be used as the WireMock instance's file source. See [Customizing the mappings directory](#customizing-the-mappings-directory) for details. +* `filesUnderDirectory`: File root that will be used as the WireMock instance's file source. See [Customizing the mappings directory](#customizing-the-mappings-directory) for details. +* `extensions`: WireMock extensions to be loaded, specified as class names. +* `extensionFactories`: WireMock extension factories to be loaded, specified as class names. +* `configurationCustomizers`: Customizer classes to be applied to the configuration object passed to the WireMock instance on construction. See [Programmatic configuration](#programmatic-configuration) for details. + + + +## Programmatic configuration +If full control over the WireMock server's configuration is needed you can supply a customizer class that can call methods directly on the +WireMock configuration object. + +```java +@EnableWireMock({ + @ConfigureWireMock( + configurationCustomizers = CustomizerTest.Customizer.class) +}) +public class CustomizerTest { + + static class Customizer implements WireMockConfigurationCustomizer { + + @Override + public void customize( + WireMockConfiguration configuration, + ConfigureWireMock options + ) { + configuration.notifier(new CustomNotifier()); + } + } +} +``` + + + +## Customizing the mappings directory +By default, each `WireMockServer` is configured to load WireMock root from: + +1. Classpath *if specified* + 1. `{specified-resource-name}/{server-name}` + 2. `{specified-resource-name}` +2. Directory + 1. `{CWD}/wiremock/{server-name}` + 2. `{CWD}/stubs/{server-name}` + 3. `{CWD}/mappings/{server-name}` + 4. `{CWD}/wiremock` + 5. `{CWD}/stubs` + 6. `{CWD}/mappings` + +This can be changed as follows: + +```java +@EnableWireMock({ + @ConfigureWireMock( + name = "fs-client", + filesUnderClasspath = "some/classpath/resource", + filesUnderDirectory = "or/a/directory") +}) +``` + +## Injecting WireMock instances into the test +Sometimes it's necessary to gain programmatic access to a running WireMock instance e.g. to configure stubs or perform verifications. + +To enable this you can inject the WireMock server into a field on the test class as follows: + +```java +@SpringBootTest(classes = InjectionTest.AppConfiguration.class) +@EnableWireMock +public class InjectionTest { + + @InjectWireMock + WireMockServer wireMock; + +} +``` + +As described in the next section you can also specify the name of the desired instance when injecting: + +```java +@SpringBootTest(classes = InjectionTest.AppConfiguration.class) +@EnableWireMock({ + @ConfigureWireMock(name = "user-service") +}) +public class InjectionTest { + + @InjectWireMock("user-service") + WireMockServer mockUserService; + + @Test + void fetch_empty_list_of_users() { + + mockUserService.stubFor(get("/users").willReturn(okJson("[]"))); + + // ... + } +} +``` + +## Running multiple instances +It's typically a good idea to run a WireMock instance per API you wish to mock, primarily to avoid clashes in the URL schemes of the two (or more) APIs. + +The Spring Boot integration supports this explictly via annotation configuration. By adding more than one configuration item, multiple instances will be +started and the associated properties added to the Spring context. + +These instances can then be injected as fields on the test class to + + +```java +@SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) +@EnableWireMock({ + @ConfigureWireMock( + name = "user-service", + baseUrlProperties = "user-service.url", + portProperties = "user-service.port"), + @ConfigureWireMock( + name = "todo-service", + baseUrlProperties = "todo-service.url", + portProperties = "todo-service.port") +}) +public class WireMockSpringExtensionTest { + + @SpringBootApplication + static class AppConfiguration {} + + @InjectWireMock("user-service") + private WireMockServer mockUserService; + + @InjectWireMock("todo-service") + private WireMockServer mockTodoService; +} +```