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:
Phillip Webb
2016-08-29 21:38:12 +01:00
parent 565ad79856
commit a985a5c861
11 changed files with 255 additions and 92 deletions

View File

@@ -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);
}

View File

@@ -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 {
}
}

View File

@@ -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();

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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();
}
}