Skip to content

Commit

Permalink
Add support for multiple property injection (#29)
Browse files Browse the repository at this point in the history
Fixes #28
---------

Co-authored-by: Maciej Walkowiak <[email protected]>
  • Loading branch information
rfelgent and maciejwalkowiak authored Sep 24, 2024
1 parent ddcc8fd commit 3938c27
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 40 deletions.
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <code>wiremock-server-name/mappings/</code>.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -91,11 +92,19 @@ private void resolveOrCreateWireMockServer(ConfigurableApplicationContext contex
});

// configure Spring environment property
List<String> 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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {

}
}

0 comments on commit 3938c27

Please sign in to comment.