Fix Mockito 2 support

See gh-7770
pull/2430/merge
Phillip Webb 8 years ago
parent f92f019418
commit c4779a10ac

@ -53,7 +53,7 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
MockitoAopProxyTargetInterceptor(Object source, Object target) throws Exception {
this.source = source;
this.target = target;
this.verification = new Verification();
this.verification = new Verification(target);
}
@Override
@ -89,7 +89,11 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
private final Object monitor = new Object();
private final MockingProgress progress = MockitoApi.get().mockingProgress();
private final MockingProgress progress;
Verification(Object target) {
this.progress = MockitoApi.get().mockingProgress(target);
}
public boolean isVerifying() {
synchronized (this.monitor) {
@ -121,7 +125,7 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
private void resetVerificationStarted(VerificationMode mode) {
ArgumentMatcherStorage storage = this.progress.getArgumentMatcherStorage();
List<LocalizedMatcher> matchers = storage.pullLocalizedMatchers();
MockitoApi.get().mockingProgress().verificationStarted(mode);
this.progress.verificationStarted(mode);
MockitoApi.get().reportMatchers(storage, matchers);
}

@ -17,16 +17,19 @@
package org.springframework.boot.test.mock.mockito;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import org.hamcrest.Matcher;
import org.mockito.Answers;
import org.mockito.internal.InternalMockHandler;
import org.mockito.internal.matchers.LocalizedMatcher;
import org.mockito.internal.progress.ArgumentMatcherStorage;
import org.mockito.internal.progress.MockingProgress;
import org.mockito.internal.progress.ThreadSafeMockingProgress;
import org.mockito.internal.stubbing.InvocationContainer;
import org.mockito.internal.util.MockUtil;
import org.mockito.internal.verification.MockAwareVerificationMode;
import org.mockito.mock.MockCreationSettings;
@ -57,9 +60,10 @@ abstract class MockitoApi {
/**
* Return the mocking progress for the current thread.
* @param mock the mock object
* @return the current mocking progress
*/
public abstract MockingProgress mockingProgress();
public abstract MockingProgress mockingProgress(Object mock);
/**
* Set report matchers to the given storage.
@ -90,11 +94,10 @@ abstract class MockitoApi {
* @return the API version
*/
private static MockitoApi createApi() {
if (!ClassUtils.isPresent("org.mockito.ReturnValues",
MockitoApi.class.getClassLoader())) {
return new Mockito2Api();
if (ClassUtils.isPresent("org.mockito.ReturnValues", null)) {
return new Mockito1Api();
}
return new Mockito1Api();
return new Mockito2Api();
}
/**
@ -105,54 +108,6 @@ abstract class MockitoApi {
return api;
}
/**
* {@link MockitoApi} for Mockito 2.0.
*/
private static class Mockito2Api extends MockitoApi {
@Override
public MockCreationSettings<?> getMockSettings(Object mock) {
return MockUtil.getMockSettings(mock);
}
@Override
public MockingProgress mockingProgress() {
return ThreadSafeMockingProgress.mockingProgress();
}
@Override
public void reportMatchers(ArgumentMatcherStorage storage,
List<LocalizedMatcher> matchers) {
for (LocalizedMatcher matcher : matchers) {
storage.reportMatcher(matcher.getMatcher());
}
}
@Override
public MockAwareVerificationMode createMockAwareVerificationMode(Object mock,
VerificationMode mode) {
try {
return new MockAwareVerificationMode(mock, mode, Collections.emptySet());
}
catch (NoSuchMethodError ex) {
// Earlier versions of 2.x did not have the collection parameter
Constructor<MockAwareVerificationMode> constructor = ClassUtils
.getConstructorIfAvailable(MockAwareVerificationMode.class,
Object.class, VerificationMode.class);
if (constructor == null) {
throw ex;
}
return BeanUtils.instantiateClass(constructor, mock, mode);
}
}
@Override
public Answer<Object> getAnswer(Answers answer) {
return answer;
}
}
/**
* {@link MockitoApi} for Mockito 1.0.
*/
@ -162,7 +117,7 @@ abstract class MockitoApi {
private final Method getMockSettingsMethod;
private final MockingProgress mockingProgress;
private final Method getMockHandlerMethod;
private Method reportMatcherMethod;
@ -172,10 +127,8 @@ abstract class MockitoApi {
this.mockUtil = BeanUtils.instantiateClass(MockUtil.class);
this.getMockSettingsMethod = ReflectionUtils.findMethod(MockUtil.class,
"getMockSettings", Object.class);
this.mockingProgress = (MockingProgress) BeanUtils
.instantiateClass(ClassUtils.resolveClassName(
"org.mockito.internal.progress.ThreadSafeMockingProgress",
MockitoApi.class.getClassLoader()));
this.getMockHandlerMethod = ReflectionUtils.findMethod(MockUtil.class,
"getMockHandler", Object.class);
this.reportMatcherMethod = ReflectionUtils.findMethod(
ArgumentMatcherStorage.class, "reportMatcher", Matcher.class);
this.mockAwareVerificationModeConstructor = ClassUtils
@ -190,8 +143,14 @@ abstract class MockitoApi {
}
@Override
public MockingProgress mockingProgress() {
return this.mockingProgress;
public MockingProgress mockingProgress(Object mock) {
InternalMockHandler<?> handler = (InternalMockHandler<?>) ReflectionUtils
.invokeMethod(this.getMockHandlerMethod, this.mockUtil, mock);
InvocationContainer container = handler.getInvocationContainer();
Field field = ReflectionUtils.findField(container.getClass(),
"mockingProgress");
ReflectionUtils.makeAccessible(field);
return (MockingProgress) ReflectionUtils.getField(field, container);
}
@Override
@ -217,4 +176,52 @@ abstract class MockitoApi {
}
/**
* {@link MockitoApi} for Mockito 2.0.
*/
private static class Mockito2Api extends MockitoApi {
@Override
public MockCreationSettings<?> getMockSettings(Object mock) {
return MockUtil.getMockSettings(mock);
}
@Override
public MockingProgress mockingProgress(Object mock) {
return ThreadSafeMockingProgress.mockingProgress();
}
@Override
public void reportMatchers(ArgumentMatcherStorage storage,
List<LocalizedMatcher> matchers) {
for (LocalizedMatcher matcher : matchers) {
storage.reportMatcher(matcher.getMatcher());
}
}
@Override
public MockAwareVerificationMode createMockAwareVerificationMode(Object mock,
VerificationMode mode) {
try {
return new MockAwareVerificationMode(mock, mode, Collections.emptySet());
}
catch (NoSuchMethodError ex) {
// Earlier versions of 2.x did not have the collection parameter
Constructor<MockAwareVerificationMode> constructor = ClassUtils
.getConstructorIfAvailable(MockAwareVerificationMode.class,
Object.class, VerificationMode.class);
if (constructor == null) {
throw ex;
}
return BeanUtils.instantiateClass(constructor, mock, mode);
}
}
@Override
public Answer<Object> getAnswer(Answers answer) {
return answer;
}
}
}

@ -20,6 +20,7 @@ import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.junit.runner.notification.Failure;
import org.springframework.boot.junit.runner.classpath.ClassPathOverrides;
import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner;
@ -43,6 +44,9 @@ public class Mockito110Tests {
private void runTests(Class<?> testClass) {
Result result = new JUnitCore().run(testClass);
for (Failure failure : result.getFailures()) {
System.err.println(failure.getTrace());
}
assertThat(result.getFailureCount()).isEqualTo(0);
assertThat(result.getRunCount()).isGreaterThan(0);
}

@ -20,6 +20,7 @@ import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.junit.runner.notification.Failure;
import org.springframework.boot.junit.runner.classpath.ClassPathOverrides;
import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner;
@ -47,6 +48,9 @@ public class Mockito21Tests {
private void runTests(Class<?> testClass) {
Result result = new JUnitCore().run(testClass);
for (Failure failure : result.getFailures()) {
System.err.println(failure.getTrace());
}
assertThat(result.getFailureCount()).isEqualTo(0);
assertThat(result.getRunCount()).isGreaterThan(0);
}

@ -20,6 +20,7 @@ import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.RunWith;
import org.junit.runner.notification.Failure;
import org.springframework.boot.junit.runner.classpath.ClassPathOverrides;
import org.springframework.boot.junit.runner.classpath.ModifiedClassPathRunner;
@ -47,6 +48,9 @@ public class Mockito22Tests {
private void runTests(Class<?> testClass) {
Result result = new JUnitCore().run(testClass);
for (Failure failure : result.getFailures()) {
System.err.println(failure.getTrace());
}
assertThat(result.getFailureCount()).isEqualTo(0);
assertThat(result.getRunCount()).isGreaterThan(0);
}

@ -16,10 +16,12 @@
package org.springframework.boot.test.mock.mockito;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.Cacheable;
@ -32,10 +34,10 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Service;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -58,8 +60,32 @@ public class SpyBeanWithAopProxyTests {
Long d2 = this.dateService.getDate(false);
assertThat(d1).isEqualTo(d2);
verify(this.dateService, times(1)).getDate(false);
verify(this.dateService, times(1)).getDate(eq(false));
verify(this.dateService, times(1)).getDate(anyBoolean());
verify(this.dateService, times(1)).getDate(matchesFalse());
verify(this.dateService, times(1)).getDate(matchesAnyBoolean());
}
private boolean matchesFalse() {
if (isTestingMockito1()) {
Method method = ReflectionUtils.findMethod(
ClassUtils.resolveClassName("org.mockito.Matchers", null), "eq",
Boolean.TYPE);
return (boolean) ReflectionUtils.invokeMethod(method, null, false);
}
return ArgumentMatchers.eq(false);
}
private boolean matchesAnyBoolean() {
if (isTestingMockito1()) {
Method method = ReflectionUtils.findMethod(
ClassUtils.resolveClassName("org.mockito.Matchers", null),
"anyBoolean");
return (boolean) ReflectionUtils.invokeMethod(method, null);
}
return ArgumentMatchers.anyBoolean();
}
private boolean isTestingMockito1() {
return ClassUtils.isPresent("org.mockito.ReturnValues", null);
}
@Configuration

Loading…
Cancel
Save