Update @MockBean to support generics
Update @MockBean and @SpyBean to support field generics. Prior to this commit the following fields would fail with a "Duplicate mock definition" exception: @MockBean private IdentityProvider<PasswordIdentity> passwordIdentityProvider; @MockBean private IdentityProvider<Oauth2Identity> oauth2IdentityProvider; Fixes gh-6602
This commit is contained in:
parent
565ad79856
commit
a985a5c861
|
|
@ -18,7 +18,6 @@ package org.springframework.boot.test.mock.mockito;
|
|||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
|
|
@ -26,6 +25,7 @@ import java.util.LinkedHashSet;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
|
@ -82,15 +82,15 @@ class DefinitionsParser {
|
|||
}
|
||||
|
||||
private void parseMockBeanAnnotation(MockBean annotation, AnnotatedElement element) {
|
||||
Set<Class<?>> classesToMock = getOrDeduceClasses(element, annotation.value());
|
||||
Assert.state(!classesToMock.isEmpty(),
|
||||
"Unable to deduce class to mock from " + element);
|
||||
Set<ResolvableType> typesToMock = getOrDeduceTypes(element, annotation.value());
|
||||
Assert.state(!typesToMock.isEmpty(),
|
||||
"Unable to deduce type to mock from " + element);
|
||||
if (StringUtils.hasLength(annotation.name())) {
|
||||
Assert.state(classesToMock.size() == 1,
|
||||
Assert.state(typesToMock.size() == 1,
|
||||
"The name attribute can only be used when mocking a single class");
|
||||
}
|
||||
for (Class<?> classToMock : classesToMock) {
|
||||
MockDefinition definition = new MockDefinition(annotation.name(), classToMock,
|
||||
for (ResolvableType typeToMock : typesToMock) {
|
||||
MockDefinition definition = new MockDefinition(annotation.name(), typeToMock,
|
||||
annotation.extraInterfaces(), annotation.answer(),
|
||||
annotation.serializable(), annotation.reset(),
|
||||
annotation.proxyTargetAware());
|
||||
|
|
@ -99,15 +99,15 @@ class DefinitionsParser {
|
|||
}
|
||||
|
||||
private void parseSpyBeanAnnotation(SpyBean annotation, AnnotatedElement element) {
|
||||
Set<Class<?>> classesToSpy = getOrDeduceClasses(element, annotation.value());
|
||||
Assert.state(!classesToSpy.isEmpty(),
|
||||
"Unable to deduce class to spy from " + element);
|
||||
Set<ResolvableType> typesToSpy = getOrDeduceTypes(element, annotation.value());
|
||||
Assert.state(!typesToSpy.isEmpty(),
|
||||
"Unable to deduce type to spy from " + element);
|
||||
if (StringUtils.hasLength(annotation.name())) {
|
||||
Assert.state(classesToSpy.size() == 1,
|
||||
Assert.state(typesToSpy.size() == 1,
|
||||
"The name attribute can only be used when spying a single class");
|
||||
}
|
||||
for (Class<?> classToSpy : classesToSpy) {
|
||||
SpyDefinition definition = new SpyDefinition(annotation.name(), classToSpy,
|
||||
for (ResolvableType typeToSpy : typesToSpy) {
|
||||
SpyDefinition definition = new SpyDefinition(annotation.name(), typeToSpy,
|
||||
annotation.reset(), annotation.proxyTargetAware());
|
||||
addDefinition(element, definition, "spy");
|
||||
}
|
||||
|
|
@ -123,13 +123,16 @@ class DefinitionsParser {
|
|||
}
|
||||
}
|
||||
|
||||
private Set<Class<?>> getOrDeduceClasses(AnnotatedElement element, Class<?>[] value) {
|
||||
Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
|
||||
classes.addAll(Arrays.asList(value));
|
||||
if (classes.isEmpty() && element instanceof Field) {
|
||||
classes.add(((Field) element).getType());
|
||||
private Set<ResolvableType> getOrDeduceTypes(AnnotatedElement element,
|
||||
Class<?>[] value) {
|
||||
Set<ResolvableType> types = new LinkedHashSet<ResolvableType>();
|
||||
for (Class<?> type : value) {
|
||||
types.add(ResolvableType.forClass(type));
|
||||
}
|
||||
return classes;
|
||||
if (types.isEmpty() && element instanceof Field) {
|
||||
types.add(ResolvableType.forField((Field) element));
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
public Set<Definition> getDefinitions() {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.mockito.MockSettings;
|
|||
import org.mockito.Mockito;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
|
@ -40,7 +41,7 @@ class MockDefinition extends Definition {
|
|||
|
||||
private static final int MULTIPLIER = 31;
|
||||
|
||||
private final Class<?> classToMock;
|
||||
private final ResolvableType typeToMock;
|
||||
|
||||
private final Set<Class<?>> extraInterfaces;
|
||||
|
||||
|
|
@ -49,15 +50,19 @@ class MockDefinition extends Definition {
|
|||
private final boolean serializable;
|
||||
|
||||
MockDefinition(Class<?> classToMock) {
|
||||
this(null, classToMock, null, null, false, null, true);
|
||||
this(ResolvableType.forClass(classToMock));
|
||||
}
|
||||
|
||||
MockDefinition(String name, Class<?> classToMock, Class<?>[] extraInterfaces,
|
||||
MockDefinition(ResolvableType typeToMock) {
|
||||
this(null, typeToMock, null, null, false, null, true);
|
||||
}
|
||||
|
||||
MockDefinition(String name, ResolvableType typeToMock, Class<?>[] extraInterfaces,
|
||||
Answers answer, boolean serializable, MockReset reset,
|
||||
boolean proxyTargetAware) {
|
||||
super(name, reset, proxyTargetAware);
|
||||
Assert.notNull(classToMock, "ClassToMock must not be null");
|
||||
this.classToMock = classToMock;
|
||||
Assert.notNull(typeToMock, "TypeToMock must not be null");
|
||||
this.typeToMock = typeToMock;
|
||||
this.extraInterfaces = asClassSet(extraInterfaces);
|
||||
this.answer = (answer != null ? answer : Answers.RETURNS_DEFAULTS);
|
||||
this.serializable = serializable;
|
||||
|
|
@ -72,11 +77,11 @@ class MockDefinition extends Definition {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return the class that should be mocked.
|
||||
* Return the type that should be mocked.
|
||||
* @return the class to mock; never {@code null}
|
||||
*/
|
||||
public Class<?> getClassToMock() {
|
||||
return this.classToMock;
|
||||
public ResolvableType getTypeToMock() {
|
||||
return this.typeToMock;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -106,7 +111,7 @@ class MockDefinition extends Definition {
|
|||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = MULTIPLIER * result + ObjectUtils.nullSafeHashCode(this.classToMock);
|
||||
result = MULTIPLIER * result + ObjectUtils.nullSafeHashCode(this.typeToMock);
|
||||
result = MULTIPLIER * result + ObjectUtils.nullSafeHashCode(this.extraInterfaces);
|
||||
result = MULTIPLIER * result + ObjectUtils.nullSafeHashCode(this.answer);
|
||||
result = MULTIPLIER * result + (this.serializable ? 1231 : 1237);
|
||||
|
|
@ -123,7 +128,7 @@ class MockDefinition extends Definition {
|
|||
}
|
||||
MockDefinition other = (MockDefinition) obj;
|
||||
boolean result = super.equals(obj);
|
||||
result &= ObjectUtils.nullSafeEquals(this.classToMock, other.classToMock);
|
||||
result &= ObjectUtils.nullSafeEquals(this.typeToMock, other.typeToMock);
|
||||
result &= ObjectUtils.nullSafeEquals(this.extraInterfaces, other.extraInterfaces);
|
||||
result &= ObjectUtils.nullSafeEquals(this.answer, other.answer);
|
||||
result &= this.serializable == other.serializable;
|
||||
|
|
@ -133,7 +138,7 @@ class MockDefinition extends Definition {
|
|||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("name", getName())
|
||||
.append("classToMock", this.classToMock)
|
||||
.append("typeToMock", this.typeToMock)
|
||||
.append("extraInterfaces", this.extraInterfaces)
|
||||
.append("answer", this.answer).append("serializable", this.serializable)
|
||||
.append("reset", getReset()).toString();
|
||||
|
|
@ -156,7 +161,7 @@ class MockDefinition extends Definition {
|
|||
if (this.serializable) {
|
||||
settings.serializable();
|
||||
}
|
||||
return (T) Mockito.mock(this.classToMock, settings);
|
||||
return (T) Mockito.mock(this.typeToMock.resolve(), settings);
|
||||
}
|
||||
|
||||
private Answer<?> getAnswer(Answers answer) {
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ import org.springframework.context.annotation.ConfigurationClassPostProcessor;
|
|||
import org.springframework.core.Conventions;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
|
@ -190,8 +191,8 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
|
||||
private RootBeanDefinition createBeanDefinition(MockDefinition mockDefinition) {
|
||||
RootBeanDefinition definition = new RootBeanDefinition(
|
||||
mockDefinition.getClassToMock());
|
||||
definition.setTargetType(mockDefinition.getClassToMock());
|
||||
mockDefinition.getTypeToMock().resolve());
|
||||
definition.setTargetType(mockDefinition.getTypeToMock());
|
||||
definition.setFactoryBeanName(BEAN_NAME);
|
||||
definition.setFactoryMethodName("createMock");
|
||||
definition.getConstructorArgumentValues().addIndexedArgumentValue(0,
|
||||
|
|
@ -216,23 +217,22 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
return mockDefinition.getName();
|
||||
}
|
||||
String[] existingBeans = getExistingBeans(beanFactory,
|
||||
mockDefinition.getClassToMock());
|
||||
mockDefinition.getTypeToMock());
|
||||
if (ObjectUtils.isEmpty(existingBeans)) {
|
||||
return this.beanNameGenerator.generateBeanName(beanDefinition, registry);
|
||||
}
|
||||
if (existingBeans.length == 1) {
|
||||
return existingBeans[0];
|
||||
}
|
||||
throw new IllegalStateException("Unable to register mock bean "
|
||||
+ mockDefinition.getClassToMock().getName()
|
||||
+ " expected a single existing bean to replace but found "
|
||||
+ new TreeSet<String>(Arrays.asList(existingBeans)));
|
||||
throw new IllegalStateException(
|
||||
"Unable to register mock bean " + mockDefinition.getTypeToMock()
|
||||
+ " expected a single existing bean to replace but found "
|
||||
+ new TreeSet<String>(Arrays.asList(existingBeans)));
|
||||
}
|
||||
|
||||
private void registerSpy(ConfigurableListableBeanFactory beanFactory,
|
||||
BeanDefinitionRegistry registry, SpyDefinition definition, Field field) {
|
||||
String[] existingBeans = getExistingBeans(beanFactory,
|
||||
definition.getClassToSpy());
|
||||
String[] existingBeans = getExistingBeans(beanFactory, definition.getTypeToSpy());
|
||||
if (ObjectUtils.isEmpty(existingBeans)) {
|
||||
createSpy(registry, definition, field);
|
||||
}
|
||||
|
|
@ -242,13 +242,14 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
}
|
||||
|
||||
private String[] getExistingBeans(ConfigurableListableBeanFactory beanFactory,
|
||||
Class<?> type) {
|
||||
ResolvableType type) {
|
||||
Set<String> beans = new LinkedHashSet<String>(
|
||||
Arrays.asList(beanFactory.getBeanNamesForType(type)));
|
||||
String resolvedTypeName = type.resolve(Object.class).getName();
|
||||
for (String beanName : beanFactory.getBeanNamesForType(FactoryBean.class)) {
|
||||
beanName = BeanFactoryUtils.transformedBeanName(beanName);
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
|
||||
if (type.getName()
|
||||
if (resolvedTypeName
|
||||
.equals(beanDefinition.getAttribute(FACTORY_BEAN_OBJECT_TYPE))) {
|
||||
beans.add(beanName);
|
||||
}
|
||||
|
|
@ -273,7 +274,7 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
private void createSpy(BeanDefinitionRegistry registry, SpyDefinition definition,
|
||||
Field field) {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(
|
||||
definition.getClassToSpy());
|
||||
definition.getTypeToSpy().resolve());
|
||||
String beanName = this.beanNameGenerator.generateBeanName(beanDefinition,
|
||||
registry);
|
||||
registry.registerBeanDefinition(beanName, beanDefinition);
|
||||
|
|
@ -283,7 +284,7 @@ public class MockitoPostProcessor extends InstantiationAwareBeanPostProcessorAda
|
|||
private void registerSpies(SpyDefinition definition, Field field,
|
||||
String[] existingBeans) {
|
||||
Assert.state(field == null || existingBeans.length == 1,
|
||||
"Unable to register spy bean " + definition.getClassToSpy().getName()
|
||||
"Unable to register spy bean " + definition.getTypeToSpy()
|
||||
+ " expected a single existing bean to replace but found "
|
||||
+ new TreeSet<String>(Arrays.asList(existingBeans)));
|
||||
for (String beanName : existingBeans) {
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ public @interface SpyBean {
|
|||
* The classes to spy. Each class specified here will result in a spy being applied.
|
||||
* Classes can be omitted when the annotation is used on a field.
|
||||
* <p>
|
||||
* When {@code @SpyBean} also defines a {@code name} this attribute can only contain
|
||||
* a single value.
|
||||
* When {@code @SpyBean} also defines a {@code name} this attribute can only contain a
|
||||
* single value.
|
||||
* <p>
|
||||
* If this is the only specified attribute consider using the {@code value} alias
|
||||
* instead.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import org.mockito.MockSettings;
|
|||
import org.mockito.Mockito;
|
||||
import org.mockito.internal.util.MockUtil;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
|
@ -36,24 +37,24 @@ class SpyDefinition extends Definition {
|
|||
|
||||
private static final int MULTIPLIER = 31;
|
||||
|
||||
private final Class<?> classToSpy;
|
||||
private final ResolvableType typeToSpy;
|
||||
|
||||
SpyDefinition(String name, Class<?> classToSpy, MockReset reset,
|
||||
SpyDefinition(String name, ResolvableType typeToSpy, MockReset reset,
|
||||
boolean proxyTargetAware) {
|
||||
super(name, reset, proxyTargetAware);
|
||||
Assert.notNull(classToSpy, "ClassToSpy must not be null");
|
||||
this.classToSpy = classToSpy;
|
||||
Assert.notNull(typeToSpy, "TypeToSpy must not be null");
|
||||
this.typeToSpy = typeToSpy;
|
||||
|
||||
}
|
||||
|
||||
public Class<?> getClassToSpy() {
|
||||
return this.classToSpy;
|
||||
public ResolvableType getTypeToSpy() {
|
||||
return this.typeToSpy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = MULTIPLIER * result + ObjectUtils.nullSafeHashCode(this.classToSpy);
|
||||
result = MULTIPLIER * result + ObjectUtils.nullSafeHashCode(this.typeToSpy);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -67,14 +68,14 @@ class SpyDefinition extends Definition {
|
|||
}
|
||||
SpyDefinition other = (SpyDefinition) obj;
|
||||
boolean result = super.equals(obj);
|
||||
result &= ObjectUtils.nullSafeEquals(this.classToSpy, other.classToSpy);
|
||||
result &= ObjectUtils.nullSafeEquals(this.typeToSpy, other.typeToSpy);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("name", getName())
|
||||
.append("classToSpy", this.classToSpy).append("reset", getReset())
|
||||
.append("typeToSpy", this.typeToSpy).append("reset", getReset())
|
||||
.toString();
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +86,7 @@ class SpyDefinition extends Definition {
|
|||
@SuppressWarnings("unchecked")
|
||||
public <T> T createSpy(String name, Object instance) {
|
||||
Assert.notNull(instance, "Instance must not be null");
|
||||
Assert.isInstanceOf(this.classToSpy, instance);
|
||||
Assert.isInstanceOf(this.typeToSpy.resolve(), instance);
|
||||
if (this.mockUtil.isSpy(instance)) {
|
||||
return (T) instance;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,15 +47,17 @@ public class DefinitionsParserTests {
|
|||
public void parseSingleMockBean() {
|
||||
this.parser.parse(SingleMockBean.class);
|
||||
assertThat(getDefinitions()).hasSize(1);
|
||||
assertThat(getMockDefinition(0).getClassToMock()).isEqualTo(ExampleService.class);
|
||||
assertThat(getMockDefinition(0).getTypeToMock().resolve())
|
||||
.isEqualTo(ExampleService.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseRepeatMockBean() {
|
||||
this.parser.parse(RepeatMockBean.class);
|
||||
assertThat(getDefinitions()).hasSize(2);
|
||||
assertThat(getMockDefinition(0).getClassToMock()).isEqualTo(ExampleService.class);
|
||||
assertThat(getMockDefinition(1).getClassToMock())
|
||||
assertThat(getMockDefinition(0).getTypeToMock().resolve())
|
||||
.isEqualTo(ExampleService.class);
|
||||
assertThat(getMockDefinition(1).getTypeToMock().resolve())
|
||||
.isEqualTo(ExampleServiceCaller.class);
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +67,7 @@ public class DefinitionsParserTests {
|
|||
assertThat(getDefinitions()).hasSize(1);
|
||||
MockDefinition definition = getMockDefinition(0);
|
||||
assertThat(definition.getName()).isEqualTo("Name");
|
||||
assertThat(definition.getClassToMock()).isEqualTo(ExampleService.class);
|
||||
assertThat(definition.getTypeToMock().resolve()).isEqualTo(ExampleService.class);
|
||||
assertThat(definition.getExtraInterfaces())
|
||||
.containsExactly(ExampleExtraInterface.class);
|
||||
assertThat(definition.getAnswer()).isEqualTo(Answers.RETURNS_SMART_NULLS);
|
||||
|
|
@ -77,8 +79,9 @@ public class DefinitionsParserTests {
|
|||
public void parseMockBeanOnClassAndField() throws Exception {
|
||||
this.parser.parse(MockBeanOnClassAndField.class);
|
||||
assertThat(getDefinitions()).hasSize(2);
|
||||
assertThat(getMockDefinition(0).getClassToMock()).isEqualTo(ExampleService.class);
|
||||
assertThat(getMockDefinition(1).getClassToMock())
|
||||
assertThat(getMockDefinition(0).getTypeToMock().resolve())
|
||||
.isEqualTo(ExampleService.class);
|
||||
assertThat(getMockDefinition(1).getTypeToMock().resolve())
|
||||
.isEqualTo(ExampleServiceCaller.class);
|
||||
}
|
||||
|
||||
|
|
@ -86,13 +89,14 @@ public class DefinitionsParserTests {
|
|||
public void parseMockBeanInferClassToMock() throws Exception {
|
||||
this.parser.parse(MockBeanInferClassToMock.class);
|
||||
assertThat(getDefinitions()).hasSize(1);
|
||||
assertThat(getMockDefinition(0).getClassToMock()).isEqualTo(ExampleService.class);
|
||||
assertThat(getMockDefinition(0).getTypeToMock().resolve())
|
||||
.isEqualTo(ExampleService.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseMockBeanMissingClassToMock() throws Exception {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Unable to deduce class to mock");
|
||||
this.thrown.expectMessage("Unable to deduce type to mock");
|
||||
this.parser.parse(MockBeanMissingClassToMock.class);
|
||||
}
|
||||
|
||||
|
|
@ -100,8 +104,9 @@ public class DefinitionsParserTests {
|
|||
public void parseMockBeanMultipleClasses() throws Exception {
|
||||
this.parser.parse(MockBeanMultipleClasses.class);
|
||||
assertThat(getDefinitions()).hasSize(2);
|
||||
assertThat(getMockDefinition(0).getClassToMock()).isEqualTo(ExampleService.class);
|
||||
assertThat(getMockDefinition(1).getClassToMock())
|
||||
assertThat(getMockDefinition(0).getTypeToMock().resolve())
|
||||
.isEqualTo(ExampleService.class);
|
||||
assertThat(getMockDefinition(1).getTypeToMock().resolve())
|
||||
.isEqualTo(ExampleServiceCaller.class);
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +122,7 @@ public class DefinitionsParserTests {
|
|||
public void parseSingleSpyBean() {
|
||||
this.parser.parse(SingleSpyBean.class);
|
||||
assertThat(getDefinitions()).hasSize(1);
|
||||
assertThat(getSpyDefinition(0).getClassToSpy())
|
||||
assertThat(getSpyDefinition(0).getTypeToSpy().resolve())
|
||||
.isEqualTo(RealExampleService.class);
|
||||
}
|
||||
|
||||
|
|
@ -125,9 +130,9 @@ public class DefinitionsParserTests {
|
|||
public void parseRepeatSpyBean() {
|
||||
this.parser.parse(RepeatSpyBean.class);
|
||||
assertThat(getDefinitions()).hasSize(2);
|
||||
assertThat(getSpyDefinition(0).getClassToSpy())
|
||||
assertThat(getSpyDefinition(0).getTypeToSpy().resolve())
|
||||
.isEqualTo(RealExampleService.class);
|
||||
assertThat(getSpyDefinition(1).getClassToSpy())
|
||||
assertThat(getSpyDefinition(1).getTypeToSpy().resolve())
|
||||
.isEqualTo(ExampleServiceCaller.class);
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +142,8 @@ public class DefinitionsParserTests {
|
|||
assertThat(getDefinitions()).hasSize(1);
|
||||
SpyDefinition definition = getSpyDefinition(0);
|
||||
assertThat(definition.getName()).isEqualTo("Name");
|
||||
assertThat(definition.getClassToSpy()).isEqualTo(RealExampleService.class);
|
||||
assertThat(definition.getTypeToSpy().resolve())
|
||||
.isEqualTo(RealExampleService.class);
|
||||
assertThat(definition.getReset()).isEqualTo(MockReset.NONE);
|
||||
}
|
||||
|
||||
|
|
@ -145,9 +151,9 @@ public class DefinitionsParserTests {
|
|||
public void parseSpyBeanOnClassAndField() throws Exception {
|
||||
this.parser.parse(SpyBeanOnClassAndField.class);
|
||||
assertThat(getDefinitions()).hasSize(2);
|
||||
assertThat(getSpyDefinition(0).getClassToSpy())
|
||||
assertThat(getSpyDefinition(0).getTypeToSpy().resolve())
|
||||
.isEqualTo(RealExampleService.class);
|
||||
assertThat(getSpyDefinition(1).getClassToSpy())
|
||||
assertThat(getSpyDefinition(1).getTypeToSpy().resolve())
|
||||
.isEqualTo(ExampleServiceCaller.class);
|
||||
}
|
||||
|
||||
|
|
@ -155,14 +161,14 @@ public class DefinitionsParserTests {
|
|||
public void parseSpyBeanInferClassToMock() throws Exception {
|
||||
this.parser.parse(SpyBeanInferClassToMock.class);
|
||||
assertThat(getDefinitions()).hasSize(1);
|
||||
assertThat(getSpyDefinition(0).getClassToSpy())
|
||||
assertThat(getSpyDefinition(0).getTypeToSpy().resolve())
|
||||
.isEqualTo(RealExampleService.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseSpyBeanMissingClassToMock() throws Exception {
|
||||
this.thrown.expect(IllegalStateException.class);
|
||||
this.thrown.expectMessage("Unable to deduce class to spy");
|
||||
this.thrown.expectMessage("Unable to deduce type to spy");
|
||||
this.parser.parse(SpyBeanMissingClassToMock.class);
|
||||
}
|
||||
|
||||
|
|
@ -170,9 +176,9 @@ public class DefinitionsParserTests {
|
|||
public void parseSpyBeanMultipleClasses() throws Exception {
|
||||
this.parser.parse(SpyBeanMultipleClasses.class);
|
||||
assertThat(getDefinitions()).hasSize(2);
|
||||
assertThat(getSpyDefinition(0).getClassToSpy())
|
||||
assertThat(getSpyDefinition(0).getTypeToSpy().resolve())
|
||||
.isEqualTo(RealExampleService.class);
|
||||
assertThat(getSpyDefinition(1).getClassToSpy())
|
||||
assertThat(getSpyDefinition(1).getTypeToSpy().resolve())
|
||||
.isEqualTo(ExampleServiceCaller.class);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.test.mock.mockito;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.mock.mockito.example.ExampleGenericService;
|
||||
import org.springframework.boot.test.mock.mockito.example.ExampleGenericServiceCaller;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
/**
|
||||
* Test {@link MockBean} on a test class field can be used to inject new mock instances.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
public class MockBeanWithGenericsOnTestFieldForNewBeanIntegrationTests {
|
||||
|
||||
@MockBean
|
||||
private ExampleGenericService<Integer> exampleIntegerService;
|
||||
|
||||
@MockBean
|
||||
private ExampleGenericService<String> exampleStringService;
|
||||
|
||||
@Autowired
|
||||
private ExampleGenericServiceCaller caller;
|
||||
|
||||
@Test
|
||||
public void testMocking() throws Exception {
|
||||
given(this.exampleIntegerService.greeting()).willReturn(200);
|
||||
given(this.exampleStringService.greeting()).willReturn("Boot");
|
||||
assertThat(this.caller.sayGreeting()).isEqualTo("I say 200 Boot");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(ExampleGenericServiceCaller.class)
|
||||
static class Config {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import org.mockito.mock.MockCreationSettings;
|
|||
|
||||
import org.springframework.boot.test.mock.mockito.example.ExampleExtraInterface;
|
||||
import org.springframework.boot.test.mock.mockito.example.ExampleService;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
|
@ -35,22 +36,25 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*/
|
||||
public class MockDefinitionTests {
|
||||
|
||||
private static final ResolvableType EXAMPLE_SERVICE_TYPE = ResolvableType
|
||||
.forClass(ExampleService.class);
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void ClassToMockMustNotBeNull() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("ClassToMock must not be null");
|
||||
this.thrown.expectMessage("TypeToMock must not be null");
|
||||
new MockDefinition(null, null, null, null, false, null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithDefaults() throws Exception {
|
||||
MockDefinition definition = new MockDefinition(null, ExampleService.class, null,
|
||||
MockDefinition definition = new MockDefinition(null, EXAMPLE_SERVICE_TYPE, null,
|
||||
null, false, null, true);
|
||||
assertThat(definition.getName()).isNull();
|
||||
assertThat(definition.getClassToMock()).isEqualTo(ExampleService.class);
|
||||
assertThat(definition.getTypeToMock()).isEqualTo(EXAMPLE_SERVICE_TYPE);
|
||||
assertThat(definition.getExtraInterfaces()).isEmpty();
|
||||
assertThat(definition.getAnswer()).isEqualTo(Answers.RETURNS_DEFAULTS);
|
||||
assertThat(definition.isSerializable()).isFalse();
|
||||
|
|
@ -59,11 +63,11 @@ public class MockDefinitionTests {
|
|||
|
||||
@Test
|
||||
public void createExplicit() throws Exception {
|
||||
MockDefinition definition = new MockDefinition("name", ExampleService.class,
|
||||
MockDefinition definition = new MockDefinition("name", EXAMPLE_SERVICE_TYPE,
|
||||
new Class<?>[] { ExampleExtraInterface.class },
|
||||
Answers.RETURNS_SMART_NULLS, true, MockReset.BEFORE, false);
|
||||
assertThat(definition.getName()).isEqualTo("name");
|
||||
assertThat(definition.getClassToMock()).isEqualTo(ExampleService.class);
|
||||
assertThat(definition.getTypeToMock()).isEqualTo(EXAMPLE_SERVICE_TYPE);
|
||||
assertThat(definition.getExtraInterfaces())
|
||||
.containsExactly(ExampleExtraInterface.class);
|
||||
assertThat(definition.getAnswer()).isEqualTo(Answers.RETURNS_SMART_NULLS);
|
||||
|
|
@ -74,7 +78,7 @@ public class MockDefinitionTests {
|
|||
|
||||
@Test
|
||||
public void createMock() throws Exception {
|
||||
MockDefinition definition = new MockDefinition("name", ExampleService.class,
|
||||
MockDefinition definition = new MockDefinition("name", EXAMPLE_SERVICE_TYPE,
|
||||
new Class<?>[] { ExampleExtraInterface.class },
|
||||
Answers.RETURNS_SMART_NULLS, true, MockReset.BEFORE, true);
|
||||
ExampleService mock = definition.createMock();
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.mockito.mock.MockCreationSettings;
|
|||
import org.springframework.boot.test.mock.mockito.example.ExampleService;
|
||||
import org.springframework.boot.test.mock.mockito.example.ExampleServiceCaller;
|
||||
import org.springframework.boot.test.mock.mockito.example.RealExampleService;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
|
@ -36,39 +37,41 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*/
|
||||
public class SpyDefinitionTests {
|
||||
|
||||
private static final ResolvableType REAL_SERVICE_TYPE = ResolvableType
|
||||
.forClass(RealExampleService.class);
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void classToSpyMustNotBeNull() throws Exception {
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("ClassToSpy must not be null");
|
||||
this.thrown.expectMessage("TypeToSpy must not be null");
|
||||
new SpyDefinition(null, null, null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithDefaults() throws Exception {
|
||||
SpyDefinition definition = new SpyDefinition(null, RealExampleService.class, null,
|
||||
true);
|
||||
SpyDefinition definition = new SpyDefinition(null, REAL_SERVICE_TYPE, null, true);
|
||||
assertThat(definition.getName()).isNull();
|
||||
assertThat(definition.getClassToSpy()).isEqualTo(RealExampleService.class);
|
||||
assertThat(definition.getTypeToSpy()).isEqualTo(REAL_SERVICE_TYPE);
|
||||
assertThat(definition.getReset()).isEqualTo(MockReset.AFTER);
|
||||
assertThat(definition.isProxyTargetAware()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createExplicit() throws Exception {
|
||||
SpyDefinition definition = new SpyDefinition("name", RealExampleService.class,
|
||||
SpyDefinition definition = new SpyDefinition("name", REAL_SERVICE_TYPE,
|
||||
MockReset.BEFORE, false);
|
||||
assertThat(definition.getName()).isEqualTo("name");
|
||||
assertThat(definition.getClassToSpy()).isEqualTo(RealExampleService.class);
|
||||
assertThat(definition.getTypeToSpy()).isEqualTo(REAL_SERVICE_TYPE);
|
||||
assertThat(definition.getReset()).isEqualTo(MockReset.BEFORE);
|
||||
assertThat(definition.isProxyTargetAware()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSpy() throws Exception {
|
||||
SpyDefinition definition = new SpyDefinition("name", RealExampleService.class,
|
||||
SpyDefinition definition = new SpyDefinition("name", REAL_SERVICE_TYPE,
|
||||
MockReset.BEFORE, true);
|
||||
RealExampleService spy = definition.createSpy(new RealExampleService("hello"));
|
||||
MockCreationSettings<?> settings = new MockUtil().getMockSettings(spy);
|
||||
|
|
@ -81,7 +84,7 @@ public class SpyDefinitionTests {
|
|||
|
||||
@Test
|
||||
public void createSpyWhenNullInstanceShouldThrowException() throws Exception {
|
||||
SpyDefinition definition = new SpyDefinition("name", RealExampleService.class,
|
||||
SpyDefinition definition = new SpyDefinition("name", REAL_SERVICE_TYPE,
|
||||
MockReset.BEFORE, true);
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("Instance must not be null");
|
||||
|
|
@ -90,7 +93,7 @@ public class SpyDefinitionTests {
|
|||
|
||||
@Test
|
||||
public void createSpyWhenWrongInstanceShouldThrowException() throws Exception {
|
||||
SpyDefinition definition = new SpyDefinition("name", RealExampleService.class,
|
||||
SpyDefinition definition = new SpyDefinition("name", REAL_SERVICE_TYPE,
|
||||
MockReset.BEFORE, true);
|
||||
this.thrown.expect(IllegalArgumentException.class);
|
||||
this.thrown.expectMessage("must be an instance of");
|
||||
|
|
@ -99,7 +102,7 @@ public class SpyDefinitionTests {
|
|||
|
||||
@Test
|
||||
public void createSpyTwice() throws Exception {
|
||||
SpyDefinition definition = new SpyDefinition("name", RealExampleService.class,
|
||||
SpyDefinition definition = new SpyDefinition("name", REAL_SERVICE_TYPE,
|
||||
MockReset.BEFORE, true);
|
||||
Object instance = new RealExampleService("hello");
|
||||
instance = definition.createSpy(instance);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.test.mock.mockito.example;
|
||||
|
||||
/**
|
||||
* Example service interface for mocking tests.
|
||||
*
|
||||
* @param <T> The generic type
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public interface ExampleGenericService<T> {
|
||||
|
||||
T greeting();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.test.mock.mockito.example;
|
||||
|
||||
/**
|
||||
* Example bean for mocking tests that calls {@link ExampleGenericService}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ExampleGenericServiceCaller {
|
||||
|
||||
private final ExampleGenericService<Integer> integerService;
|
||||
|
||||
private final ExampleGenericService<String> stringService;
|
||||
|
||||
public ExampleGenericServiceCaller(ExampleGenericService<Integer> integerService,
|
||||
ExampleGenericService<String> stringService) {
|
||||
this.integerService = integerService;
|
||||
this.stringService = stringService;
|
||||
}
|
||||
|
||||
public ExampleGenericService<Integer> getIntegerService() {
|
||||
return this.integerService;
|
||||
}
|
||||
|
||||
public ExampleGenericService<String> getStringService() {
|
||||
return this.stringService;
|
||||
}
|
||||
|
||||
public String sayGreeting() {
|
||||
return "I say " + +this.integerService.greeting() + " "
|
||||
+ this.stringService.greeting();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue