Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-28: add support for multiple property injection #29

Merged
merged 13 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
}
rfelgent marked this conversation as resolved.
Show resolved Hide resolved
}

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 {

}
}
Loading