Skip to content

Commit b7ff305

Browse files
authored
Isolation from package-protected spring boot test code (#2)
1 parent 44dbbb5 commit b7ff305

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+222
-177
lines changed

README.MD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ Simply include the maven dependency (from central maven) to start using @MockInB
8686
<dependency>
8787
<groupId>com.teketik</groupId>
8888
<artifactId>mock-in-bean</artifactId>
89-
<version>boot2-v1.0</version>
89+
<version>boot2-v1.1</version>
9090
<scope>test</scope>
9191
</dependency>
9292
```

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<modelVersion>4.0.0</modelVersion>
66
<groupId>com.teketik</groupId>
77
<artifactId>mock-in-bean</artifactId>
8-
<version>boot2-v1.0-SNAPSHOT</version>
8+
<version>boot2-v1.1-SNAPSHOT</version>
99
<name>Mock in Bean</name>
1010
<description>Surgically Inject Mockito Mock/Spy in Spring Beans</description>
1111
<url>https://github.com/antoinemeyer/mock-in-bean</url>

src/main/java/org/springframework/boot/test/mock/mockito/BeanFieldState.java renamed to src/main/java/com/teketik/test/mockinbean/BeanFieldState.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.springframework.boot.test.mock.mockito;
1+
package com.teketik.test.mockinbean;
22

33
import org.springframework.test.context.TestContext;
44

@@ -8,7 +8,7 @@ class BeanFieldState extends FieldState {
88

99
private Object bean;
1010

11-
public BeanFieldState(Object bean, Field field, Object originalValue, DefinitionFacade definition) {
11+
public BeanFieldState(Object bean, Field field, Object originalValue, Definition definition) {
1212
super(field, originalValue, definition);
1313
this.bean = bean;
1414
}

src/main/java/org/springframework/boot/test/mock/mockito/BeanUtils.java renamed to src/main/java/com/teketik/test/mockinbean/BeanUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.springframework.boot.test.mock.mockito;
1+
package com.teketik.test.mockinbean;
22

33
import org.springframework.context.ApplicationContext;
44
import org.springframework.lang.Nullable;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.teketik.test.mockinbean;
2+
3+
import org.mockito.Mock;
4+
import org.mockito.Spy;
5+
import org.springframework.core.ResolvableType;
6+
7+
import java.util.Objects;
8+
9+
/**
10+
* <p>Definition of a {@link Mock mock} or a {@link Spy spy}.
11+
* <p>Corresponding entity can be created using {@link #create(Object)}.
12+
* @author Antoine Meyer
13+
*/
14+
abstract class Definition {
15+
16+
protected final String name;
17+
protected final ResolvableType resolvableType;
18+
19+
Definition(String name, ResolvableType resolvableType) {
20+
super();
21+
this.name = name;
22+
this.resolvableType = resolvableType;
23+
}
24+
25+
String getName() {
26+
return name;
27+
}
28+
29+
ResolvableType getResolvableType() {
30+
return resolvableType;
31+
}
32+
33+
/**
34+
* Creates a mock or a spy of the provided original value.
35+
* @param <T>
36+
* @param originalValue
37+
* @return
38+
*/
39+
abstract <T> T create(Object originalValue);
40+
41+
@Override
42+
public int hashCode() {
43+
return Objects.hash(name, resolvableType);
44+
}
45+
46+
@Override
47+
public boolean equals(Object obj) {
48+
if (this == obj) {
49+
return true;
50+
}
51+
if (obj == null) {
52+
return false;
53+
}
54+
if (getClass() != obj.getClass()) {
55+
return false;
56+
}
57+
Definition other = (Definition) obj;
58+
return Objects.equals(name, other.name) && Objects.equals(resolvableType, other.resolvableType);
59+
}
60+
61+
@Override
62+
public String toString() {
63+
return "Definition [name=" + name + ", resolvableType=" + resolvableType + "]";
64+
}
65+
66+
}

src/main/java/org/springframework/boot/test/mock/mockito/FieldState.java renamed to src/main/java/com/teketik/test/mockinbean/FieldState.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.springframework.boot.test.mock.mockito;
1+
package com.teketik.test.mockinbean;
22

33
import org.springframework.lang.Nullable;
44
import org.springframework.test.context.TestContext;
@@ -12,14 +12,14 @@ abstract class FieldState {
1212
@Nullable
1313
final Object originalValue;
1414

15-
final DefinitionFacade definition;
15+
final Definition definition;
1616

17-
public FieldState(Field targetField, Object originalValue, DefinitionFacade definition) {
17+
public FieldState(Field targetField, Object originalValue, Definition definition) {
1818
this.field = targetField;
1919
this.originalValue = originalValue;
2020
this.definition = definition;
2121
}
2222

23-
public abstract Object resolveTarget(TestContext testContext);
23+
abstract Object resolveTarget(TestContext testContext);
2424

2525
}

src/main/java/org/springframework/boot/test/mock/mockito/InBeanDefinition.java renamed to src/main/java/com/teketik/test/mockinbean/InBeanDefinition.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
package org.springframework.boot.test.mock.mockito;
2-
3-
import com.teketik.test.mockinbean.MockInBean;
4-
import com.teketik.test.mockinbean.SpyInBean;
1+
package com.teketik.test.mockinbean;
52

63
import org.springframework.lang.Nullable;
74

@@ -16,7 +13,7 @@ class InBeanDefinition {
1613
@Nullable
1714
final String name;
1815

19-
public InBeanDefinition(Class<?> clazz, String name) {
16+
InBeanDefinition(Class<?> clazz, String name) {
2017
super();
2118
this.clazz = clazz;
2219
this.name = name;
Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
package org.springframework.boot.test.mock.mockito;
2-
3-
import com.teketik.test.mockinbean.MockInBean;
4-
import com.teketik.test.mockinbean.SpyInBean;
1+
package com.teketik.test.mockinbean;
52

63
import org.springframework.core.ResolvableType;
74
import org.springframework.core.annotation.MergedAnnotation;
@@ -23,13 +20,13 @@
2320
import java.util.Set;
2421

2522
/**
26-
* <p>Similar to {@link DefinitionsParser} but handles {@link MockInBean} and {@link SpyInBean}.
23+
* <p>Similar to {@link org.springframework.boot.test.mock.mockito.DefinitionsParser} but handles {@link MockInBean} and {@link SpyInBean}.
2724
* <p>Every mock/spy {@link Definition} maps to one or more {@link InBeanDefinition}.
2825
* @see DefinitionsParser
2926
*/
3027
class InBeanDefinitionsParser {
3128

32-
private final Map<DefinitionFacade, List<InBeanDefinition>> definitions = new HashMap<DefinitionFacade, List<InBeanDefinition>>();
29+
private final Map<Definition, List<InBeanDefinition>> definitions = new HashMap<Definition, List<InBeanDefinition>>();
3330

3431
void parse(Class<?> source) {
3532
ReflectionUtils.doWithFields(source, (field) -> parseField(field, source));
@@ -51,33 +48,35 @@ private void parseMockInBeanAnnotation(MockInBean annotation, Field field, Class
5148
final Set<ResolvableType> typesToMock = getOrDeduceTypes(field, source);
5249
Assert.state(!typesToMock.isEmpty(), () -> "Unable to deduce type to mock from " + field);
5350
for (ResolvableType typeToMock : typesToMock) {
54-
final MockDefinition mockDefinition = new MockDefinition(field.getName(), typeToMock, new Class[] {}, null, false, MockReset.AFTER, QualifierDefinition.forElement(field));
55-
InBeanDefinition inBeanDefinition = new InBeanDefinition(
51+
final Definition definition = new MockDefinition(
52+
field.getName(),
53+
typeToMock
54+
);
55+
final InBeanDefinition inBeanDefinition = new InBeanDefinition(
5656
annotation.value(),
5757
StringUtils.isEmpty(annotation.name()) ? null : annotation.name()
5858
);
59-
addDefinition(mockDefinition, inBeanDefinition);
59+
addDefinition(definition, inBeanDefinition);
6060
}
6161
}
6262

6363
private void parseSpyInBeanAnnotation(SpyInBean annotation, Field field, Class<?> source) {
6464
final Set<ResolvableType> typesToSpy = getOrDeduceTypes(field, source);
6565
Assert.state(!typesToSpy.isEmpty(), () -> "Unable to deduce type to spy from " + field);
6666
for (ResolvableType typeToSpy : typesToSpy) {
67-
final SpyDefinition spyDefinition = new SpyDefinition(field.getName(), typeToSpy, MockReset.AFTER, true, QualifierDefinition.forElement(field));
68-
InBeanDefinition inBeanDefinition = new InBeanDefinition(
67+
final Definition definition = new SpyDefinition(
68+
field.getName(),
69+
typeToSpy
70+
);
71+
final InBeanDefinition inBeanDefinition = new InBeanDefinition(
6972
annotation.value(),
7073
StringUtils.isEmpty(annotation.name()) ? null : annotation.name()
7174
);
72-
addDefinition(spyDefinition, inBeanDefinition);
75+
addDefinition(definition, inBeanDefinition);
7376
}
7477
}
7578

7679
private void addDefinition(Definition definition, InBeanDefinition inBeanDefinition) {
77-
addDefinition(new DefinitionFacade(definition), inBeanDefinition);
78-
}
79-
80-
private void addDefinition(DefinitionFacade definition, InBeanDefinition inBeanDefinition) {
8180
List<InBeanDefinition> inBeanBaseDefinitions = definitions.get(definition);
8281
if (inBeanBaseDefinitions == null) {
8382
inBeanBaseDefinitions = new LinkedList<InBeanDefinition>();
@@ -99,7 +98,7 @@ private Set<ResolvableType> getOrDeduceTypes(AnnotatedElement element, Class<?>
9998
return types;
10099
}
101100

102-
public Map<DefinitionFacade, List<InBeanDefinition>> getDefinitions() {
101+
public Map<Definition, List<InBeanDefinition>> getDefinitions() {
103102
return Collections.unmodifiableMap(definitions);
104103
}
105104

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.teketik.test.mockinbean;
2+
3+
import static org.mockito.Mockito.mock;
4+
5+
import org.mockito.MockSettings;
6+
import org.springframework.boot.test.mock.mockito.MockReset;
7+
import org.springframework.core.ResolvableType;
8+
9+
class MockDefinition extends Definition {
10+
11+
MockDefinition(String name, ResolvableType type) {
12+
super(name, type);
13+
}
14+
15+
@Override
16+
<T> T create(Object originalValue) {
17+
MockSettings settings = MockReset.withSettings(MockReset.AFTER);
18+
settings.name(name);
19+
return (T) mock(resolvableType.resolve(), settings);
20+
}
21+
22+
}
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.springframework.boot.test.mock.mockito;
1+
package com.teketik.test.mockinbean;
22

33
import org.mockito.Mock;
44
import org.mockito.Spy;
@@ -38,9 +38,9 @@ public void beforeTestClass(TestContext testContext) throws Exception {
3838
parser.parse(testContext.getTestClass());
3939
final Set<Field> visitedFields = new HashSet<>();
4040
final LinkedList<FieldState> originalValues = new LinkedList<>();
41-
for (Entry<DefinitionFacade, List<InBeanDefinition>> definitionToInbeans : parser.getDefinitions().entrySet()) {
42-
final DefinitionFacade definition = definitionToInbeans.getKey();
43-
final Class<?> mockOrSpyType = definition.getType();
41+
for (Entry<Definition, List<InBeanDefinition>> definitionToInbeans : parser.getDefinitions().entrySet()) {
42+
final Definition definition = definitionToInbeans.getKey();
43+
final Class<?> mockOrSpyType = (Class<?>) definition.getResolvableType().getType();
4444
Field beanField = null;
4545
for (InBeanDefinition inBeanDefinition : definitionToInbeans.getValue()) {
4646
beanField = BeanUtils.findField(inBeanDefinition.clazz, definition.getName(), mockOrSpyType);
@@ -79,12 +79,12 @@ public void beforeTestClass(TestContext testContext) throws Exception {
7979
*/
8080
@Override
8181
public void beforeTestMethod(TestContext testContext) throws Exception {
82-
final Map<DefinitionFacade, Object> mockOrSpys = new HashMap<>();
82+
final Map<Definition, Object> mockOrSpys = new HashMap<>();
8383
((LinkedList<FieldState>) testContext.getAttribute(ORIGINAL_VALUES_ATTRIBUTE_NAME))
8484
.forEach(fieldState -> {
8585
Object mockOrSpy = mockOrSpys.get(fieldState.definition);
8686
if (mockOrSpy == null) {
87-
mockOrSpy = fieldState.definition.makeMockOrSpy(fieldState.originalValue);
87+
mockOrSpy = fieldState.definition.create(fieldState.originalValue);
8888
mockOrSpys.put(fieldState.definition, mockOrSpy);
8989
}
9090
ReflectionUtils.setField(
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.teketik.test.mockinbean;
2+
3+
import org.mockito.MockSettings;
4+
import org.mockito.Mockito;
5+
import org.springframework.boot.test.mock.mockito.MockReset;
6+
import org.springframework.core.ResolvableType;
7+
import org.springframework.util.Assert;
8+
9+
class SpyDefinition extends Definition {
10+
11+
SpyDefinition(String name, ResolvableType type) {
12+
super(name, type);
13+
}
14+
15+
@Override
16+
<T> T create(Object originalValue) {
17+
Assert.notNull(originalValue, "originalValue must not be null");
18+
Assert.isInstanceOf(this.resolvableType.resolve(), originalValue);
19+
Assert.state(!Mockito.mockingDetails(originalValue).isSpy(), "originalValue is already a spy");
20+
MockSettings settings = MockReset.withSettings(MockReset.AFTER);
21+
settings.name(name);
22+
settings.spiedInstance(originalValue);
23+
settings.defaultAnswer(Mockito.CALLS_REAL_METHODS);
24+
return (T) Mockito.mock(originalValue.getClass(), settings);
25+
}
26+
27+
}

src/main/java/org/springframework/boot/test/mock/mockito/TestFieldState.java renamed to src/main/java/com/teketik/test/mockinbean/TestFieldState.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
package org.springframework.boot.test.mock.mockito;
1+
package com.teketik.test.mockinbean;
22

33
import org.springframework.test.context.TestContext;
44

55
import java.lang.reflect.Field;
66

77
class TestFieldState extends FieldState {
88

9-
public TestFieldState(Field targetField, Object originalValue, DefinitionFacade definition) {
9+
TestFieldState(Field targetField, Object originalValue, Definition definition) {
1010
super(targetField, originalValue, definition);
1111
}
1212

1313
@Override
14-
public Object resolveTarget(TestContext testContext) {
14+
Object resolveTarget(TestContext testContext) {
1515
return testContext.getTestInstance();
1616
}
1717

0 commit comments

Comments
 (0)