diff --git a/README.md b/README.md index ed7a927..36d7c52 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,58 @@ WireMock extensions can be registered independently with each `@ConfigureWireMoc @ConfigureWireMock(name = "...", property = "...", extensions = { ... }) ``` +### Single vs Multiple Property Injection + +The concept of single property injection can be described as wiring _one_ `WireMockServer` instance to _one_ property. + +```java +@SpringBootTest +@EnableWireMock({ + @ConfigureWireMock(name = "foo-service", property = "app.client-apis.foo.base-path"}), + @ConfigureWireMock(name = "bar-service", property = "app.client-apis.bar.base-path"}), + @ConfigureWireMock(name = "mojo-service", property = "app.client-apis.mojo.base-path"}) +}) +class AppIT { + @InjectWireMock("foo-service") + private WireMockServer fooService; + @InjectWireMock("bar-service") + private WireMockServer barService; + @InjectWireMock("mojo-service") + private WireMockServer mojoService; + + @Test + void contextLoads() { + // your test code + } +} +``` + +The concept of multiple property injection can be described as wiring _one_ `WireMockServer` instance to _multiple_ properties. + +```java +@SpringBootTest +@EnableWireMock({ + @ConfigureWireMock(name = "services", properties = { + "app.client-apis.foo.base-path", + "app.client-apis.bar.base-path", + "app.client-apis.mojo.base-path"}) +}) +class AppIT { + + @InjectWireMock("services") + private WireMockServer services; + + @Test + void contextLoads() { + // your test code + } +} +``` + +The *single* property injection provides a high level of isolation when mocking and stubbing 3rd pary RESTful api, because every service +is associated to its own dedicated `WireMockServer` instance. +The *multiple* property injections provides a less complex test setup at the cost of isolation. + ### Customizing mappings directory By default, each `WireMockServer` is configured to load mapping files from a classpath directory `wiremock/{server-name}/mappings`. diff --git a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java index 723d38b..4a22b02 100644 --- a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java +++ b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/ConfigureWireMock.java @@ -32,10 +32,18 @@ /** * The name of Spring property to inject the {@link WireMockServer#baseUrl()} * + * @deprecated please use {@link ConfigureWireMock#properties()} * @return the name of Spring property to inject the {@link WireMockServer#baseUrl()} */ + @Deprecated(since = "2.1.3") String property() default ""; + /** + * Names of Spring properties to inject the {@link WireMockServer#baseUrl()}. + * + * @return names of Spring properties to inject the {@link WireMockServer#baseUrl()}. + */ + String[] properties() default {}; /** * The location of WireMock stub files. By default, stubs are resolved from classpath location wiremock-server-name/mappings/. * diff --git a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java index 94ddcb2..e7e62be 100644 --- a/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java +++ b/wiremock-spring-boot/src/main/java/com/maciejwalkowiak/wiremock/spring/WireMockContextCustomizer.java @@ -7,6 +7,7 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.common.Notifier; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import java.util.stream.Collectors; import org.junit.platform.commons.util.ReflectionUtils; import org.junit.platform.commons.util.StringUtils; import org.slf4j.Logger; @@ -91,11 +92,19 @@ private void resolveOrCreateWireMockServer(ConfigurableApplicationContext contex }); // configure Spring environment property + List propertyNames; if (StringUtils.isNotBlank(options.property())) { - String property = options.property() + "=" + newServer.baseUrl(); + propertyNames = List.of(options.property()); + } else { + propertyNames = Arrays.stream(options.properties()) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toList()); + } + propertyNames.forEach(propertyName -> { + String property = propertyName + "=" + newServer.baseUrl(); LOGGER.debug("Adding property '{}' to Spring application context", property); TestPropertyValues.of(property).applyTo(context.getEnvironment()); - } + }); } else { LOGGER.info("WireMockServer with name '{}' is already configured", options.name()); } diff --git a/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java b/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java index 8a11925..0a13647 100644 --- a/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java +++ b/wiremock-spring-boot/src/test/java/app/WireMockSpringExtensionTest.java @@ -4,6 +4,7 @@ import com.maciejwalkowiak.wiremock.spring.ConfigureWireMock; import com.maciejwalkowiak.wiremock.spring.EnableWireMock; import com.maciejwalkowiak.wiremock.spring.InjectWireMock; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -13,54 +14,85 @@ import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) -@EnableWireMock({ - @ConfigureWireMock(name = "user-service", property = "user-service.url"), - @ConfigureWireMock(name = "todo-service", property = "todo-service.url"), - @ConfigureWireMock(name = "noproperty-service") -}) public class WireMockSpringExtensionTest { - @SpringBootApplication - static class AppConfiguration { + @SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) + @EnableWireMock({ + @ConfigureWireMock(name = "user-service", property = "user-service.url"), + @ConfigureWireMock(name = "todo-service", property = "todo-service.url"), + @ConfigureWireMock(name = "noproperty-service") + }) + @Nested + class SinglePropertyBindingTest { - } + @InjectWireMock("todo-service") + private WireMockServer todoWireMockServer; - @InjectWireMock("todo-service") - private WireMockServer todoWireMockServer; + @Autowired + private Environment environment; - @Autowired - private Environment environment; + @Test + void createsWiremockWithClassLevelConfigureWiremock(@InjectWireMock("user-service") WireMockServer wireMockServer) { + assertWireMockServer(wireMockServer, "user-service.url"); + } - @Test - void createsWiremockWithClassLevelConfigureWiremock(@InjectWireMock("user-service") WireMockServer wireMockServer) { - assertWireMockServer(wireMockServer, "user-service.url"); - } + @Test + void createsWiremockWithFieldLevelConfigureWiremock() { + assertWireMockServer(todoWireMockServer, "todo-service.url"); + } + + @Test + void doesNotSetPropertyWhenNotProvided(@InjectWireMock("noproperty-service") WireMockServer wireMockServer) { + assertThat(wireMockServer) + .as("inject wiremock sets null when not configured") + .isNotNull(); + } - @Test - void createsWiremockWithFieldLevelConfigureWiremock() { - assertWireMockServer(todoWireMockServer, "todo-service.url"); + private void assertWireMockServer(WireMockServer wireMockServer, String property) { + assertThat(wireMockServer) + .as("creates WireMock instance") + .isNotNull(); + assertThat(wireMockServer.baseUrl()) + .as("WireMock baseUrl is set") + .isNotNull(); + assertThat(wireMockServer.port()) + .as("sets random port") + .isNotZero(); + assertThat(environment.getProperty(property)) + .as("sets Spring property") + .isEqualTo(wireMockServer.baseUrl()); + } } - @Test - void doesNotSetPropertyWhenNotProvided(@InjectWireMock("noproperty-service") WireMockServer wireMockServer) { - assertThat(wireMockServer) - .as("creates WireMock instance") - .isNotNull(); + @SpringBootTest(classes = WireMockSpringExtensionTest.AppConfiguration.class) + @EnableWireMock({ + @ConfigureWireMock(name = "user-service", properties = {"user-service.url", "todo-service.url"}), + @ConfigureWireMock(name = "mojo-service", property = "mojo-service.url", properties = {"other-service.url"}) + }) + @Nested + class MultiplePropertiesBindingTest { + + @InjectWireMock("user-service") + private WireMockServer userServiceWireMockServer; + + @InjectWireMock("mojo-service") + private WireMockServer mojoServiceWireMockServer; + + @Autowired + private Environment environment; + + @Test + void bindsUrlToMultipleProperties() { + assertThat(environment.getProperty("user-service.url")).isEqualTo(userServiceWireMockServer.baseUrl()); + assertThat(environment.getProperty("todo-service.url")).isEqualTo(userServiceWireMockServer.baseUrl()); + // single property binding takes precedence over multiple properties binding + assertThat(environment.getProperty("mojo-service.url")).isEqualTo(mojoServiceWireMockServer.baseUrl()); + assertThat(environment.getProperty("other-service.url")).isNull(); + } } - private void assertWireMockServer(WireMockServer wireMockServer, String property) { - assertThat(wireMockServer) - .as("creates WireMock instance") - .isNotNull(); - assertThat(wireMockServer.baseUrl()) - .as("WireMock baseUrl is set") - .isNotNull(); - assertThat(wireMockServer.port()) - .as("sets random port") - .isNotZero(); - assertThat(environment.getProperty(property)) - .as("sets Spring property") - .isEqualTo(wireMockServer.baseUrl()); + @SpringBootApplication + static class AppConfiguration { + } }