Skip to content

Commit

Permalink
fix: give helpful error message when using same name in mocks (refs #62)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasbjerre committed Nov 2, 2024
1 parent fdb382c commit 5725b1c
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
Expand All @@ -12,65 +16,78 @@
import org.wiremock.spring.EnableWireMock;

/**
* Creates {@link WireMockContextCustomizer} for test classes annotated with {@link EnableWireMock}.
* Creates {@link WireMockContextCustomizer} for test classes annotated with
* {@link EnableWireMock}.
*
* @author Maciej Walkowiak
*/
public class WireMockContextCustomizerFactory implements ContextCustomizerFactory {
static final ConfigureWireMock DEFAULT_CONFIGURE_WIREMOCK =
DefaultConfigureWireMock.class.getAnnotation(ConfigureWireMock.class);
static final ConfigureWireMock DEFAULT_CONFIGURE_WIREMOCK = DefaultConfigureWireMock.class
.getAnnotation(ConfigureWireMock.class);

@ConfigureWireMock(name = "wiremock")
private static class DefaultConfigureWireMock {
}

@ConfigureWireMock(name = "wiremock")
private static class DefaultConfigureWireMock {}
static ConfigureWireMock[] getConfigureWireMocksOrDefault(final ConfigureWireMock... configureWireMock) {
if (configureWireMock == null || configureWireMock.length == 0) {
return new ConfigureWireMock[] { WireMockContextCustomizerFactory.DEFAULT_CONFIGURE_WIREMOCK };
}
return configureWireMock;
}

static ConfigureWireMock[] getConfigureWireMocksOrDefault(final ConfigureWireMock... value) {
if (value == null || value.length == 0) {
return new ConfigureWireMock[] {WireMockContextCustomizerFactory.DEFAULT_CONFIGURE_WIREMOCK};
}
return value;
}
@Override
public ContextCustomizer createContextCustomizer(final Class<?> testClass,
final List<ContextConfigurationAttributes> configAttributes) {
// scan class and all enclosing classes if the test class is @Nested
final ConfigureWiremockHolder holder = new ConfigureWiremockHolder();
this.parseDefinitions(testClass, holder);

@Override
public ContextCustomizer createContextCustomizer(
final Class<?> testClass, final List<ContextConfigurationAttributes> configAttributes) {
// scan class and all enclosing classes if the test class is @Nested
final ConfigureWiremockHolder holder = new ConfigureWiremockHolder();
this.parseDefinitions(testClass, holder);
if (holder.isEmpty()) {
return null;
} else {
return new WireMockContextCustomizer(holder.asArray());
}
}

if (holder.isEmpty()) {
return null;
} else {
return new WireMockContextCustomizer(holder.asArray());
}
}
private void parseDefinitions(final Class<?> testClass, final ConfigureWiremockHolder parser) {
parser.parse(testClass);
if (TestContextAnnotationUtils.searchEnclosingClass(testClass)) {
this.parseDefinitions(testClass.getEnclosingClass(), parser);
}
}

private void parseDefinitions(final Class<?> testClass, final ConfigureWiremockHolder parser) {
parser.parse(testClass);
if (TestContextAnnotationUtils.searchEnclosingClass(testClass)) {
this.parseDefinitions(testClass.getEnclosingClass(), parser);
}
}
private static class ConfigureWiremockHolder {
private final List<ConfigureWireMock> annotations = new ArrayList<>();

private static class ConfigureWiremockHolder {
private final List<ConfigureWireMock> annotations = new ArrayList<>();
void add(final ConfigureWireMock... annotations) {
this.annotations.addAll(Arrays.asList(annotations));
this.sanityCheckDuplicateNames(this.annotations);
}

void add(final ConfigureWireMock... annotations) {
this.annotations.addAll(Arrays.asList(annotations));
}
void parse(final Class<?> clazz) {
final EnableWireMock annotation = AnnotationUtils.findAnnotation(clazz, EnableWireMock.class);
if (annotation != null) {
this.add(getConfigureWireMocksOrDefault(annotation.value()));
}
}

void parse(final Class<?> clazz) {
final EnableWireMock annotation = AnnotationUtils.findAnnotation(clazz, EnableWireMock.class);
if (annotation != null) {
this.add(getConfigureWireMocksOrDefault(annotation.value()));
}
}
private void sanityCheckDuplicateNames(final List<ConfigureWireMock> check) {
final List<String> names = check.stream().map(it -> it.name()).toList();
final Set<String> dublicateNames = names.stream().filter(it -> Collections.frequency(names, it) > 1)
.collect(Collectors.toSet());
if (!dublicateNames.isEmpty()) {
throw new IllegalStateException("Names of mocks must be unique, found duplicates of: "
+ dublicateNames.stream().sorted().collect(Collectors.joining(",")));
}
}

boolean isEmpty() {
return this.annotations.isEmpty();
}
boolean isEmpty() {
return this.annotations.isEmpty();
}

ConfigureWireMock[] asArray() {
return this.annotations.toArray(new ConfigureWireMock[] {});
}
}
ConfigureWireMock[] asArray() {
return this.annotations.toArray(new ConfigureWireMock[] {});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.wiremock.spring.test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertThrows;

import org.junit.jupiter.api.Test;
import org.wiremock.spring.ConfigureWireMock;
import org.wiremock.spring.EnableWireMock;
import org.wiremock.spring.internal.WireMockContextCustomizerFactory;

class ConfigurationValidationTest {

@EnableWireMock({ @ConfigureWireMock, @ConfigureWireMock })
private static class EnableWireMockSameDefaultName {
}

@EnableWireMock({ @ConfigureWireMock(name = "w1"), @ConfigureWireMock(name = "w1") })
private static class EnableWireMockSameGivenName {
}

@Test
void testDuplicateNames_default() {
final IllegalStateException thrown = assertThrows(IllegalStateException.class,
() -> new WireMockContextCustomizerFactory()
.createContextCustomizer(EnableWireMockSameDefaultName.class, null));
assertThat(thrown.getMessage()).isEqualTo("Names of mocks must be unique, found duplicates of: wiremock");
}

@Test
void testDuplicateNames_given() {
final IllegalStateException thrown = assertThrows(IllegalStateException.class,
() -> new WireMockContextCustomizerFactory().createContextCustomizer(EnableWireMockSameGivenName.class,
null));
assertThat(thrown.getMessage()).isEqualTo("Names of mocks must be unique, found duplicates of: w1");
}

}

0 comments on commit 5725b1c

Please sign in to comment.