Polish Mockito 2.0 support
This commit is contained in:
parent
565f75438e
commit
abb8e3663a
|
@ -105,7 +105,7 @@ public enum MockReset {
|
|||
MockReset reset = MockReset.NONE;
|
||||
if (ClassUtils.isPresent("org.mockito.internal.util.MockUtil", null)) {
|
||||
if (Mockito.mockingDetails(mock).isMock()) {
|
||||
MockCreationSettings settings = SpringBootMockUtil.getMockSettings(mock);
|
||||
MockCreationSettings settings = MockitoApi.get().getMockSettings(mock);
|
||||
List listeners = settings.getInvocationListeners();
|
||||
for (Object listener : listeners) {
|
||||
if (listener instanceof ResetInvocationListener) {
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.aopalliance.intercept.MethodInterceptor;
|
|||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.mockito.internal.matchers.LocalizedMatcher;
|
||||
import org.mockito.internal.progress.ArgumentMatcherStorage;
|
||||
import org.mockito.internal.progress.MockingProgress;
|
||||
import org.mockito.internal.verification.MockAwareVerificationMode;
|
||||
import org.mockito.verification.VerificationMode;
|
||||
|
||||
|
@ -52,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
|
||||
|
@ -88,10 +89,15 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
|
|||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
private final MockingProgress progress;
|
||||
|
||||
public Verification(Object target) {
|
||||
this.progress = MockitoApi.get().mockingProgress(target);
|
||||
}
|
||||
|
||||
public boolean isVerifying() {
|
||||
synchronized (this.monitor) {
|
||||
VerificationMode mode = SpringBootMockUtil.mockingProgress()
|
||||
.pullVerificationMode();
|
||||
VerificationMode mode = this.progress.pullVerificationMode();
|
||||
if (mode != null) {
|
||||
resetVerificationStarted(mode);
|
||||
return true;
|
||||
|
@ -102,13 +108,13 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
|
|||
|
||||
public void replaceVerifyMock(Object source, Object target) {
|
||||
synchronized (this.monitor) {
|
||||
VerificationMode mode = SpringBootMockUtil.mockingProgress()
|
||||
.pullVerificationMode();
|
||||
VerificationMode mode = this.progress.pullVerificationMode();
|
||||
if (mode != null) {
|
||||
if (mode instanceof MockAwareVerificationMode) {
|
||||
MockAwareVerificationMode mockAwareMode = (MockAwareVerificationMode) mode;
|
||||
if (mockAwareMode.getMock() == source) {
|
||||
mode = new MockAwareVerificationMode(target, mockAwareMode);
|
||||
mode = MockitoApi.get().createMockAwareVerificationMode(
|
||||
target, mockAwareMode);
|
||||
}
|
||||
}
|
||||
resetVerificationStarted(mode);
|
||||
|
@ -117,11 +123,10 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor {
|
|||
}
|
||||
|
||||
private void resetVerificationStarted(VerificationMode mode) {
|
||||
ArgumentMatcherStorage storage = SpringBootMockUtil.mockingProgress()
|
||||
.getArgumentMatcherStorage();
|
||||
ArgumentMatcherStorage storage = this.progress.getArgumentMatcherStorage();
|
||||
List<LocalizedMatcher> matchers = storage.pullLocalizedMatchers();
|
||||
SpringBootMockUtil.mockingProgress().verificationStarted(mode);
|
||||
SpringBootMockUtil.reportMatchers(storage, matchers);
|
||||
this.progress.verificationStarted(mode);
|
||||
MockitoApi.get().reportMatchers(storage, matchers);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* 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 java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
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;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.mockito.verification.VerificationMode;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A facade for Mockito APIs that have changed between Mockito 1 and Mockito 2.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
abstract class MockitoApi {
|
||||
|
||||
private static final MockitoApi api = createApi();
|
||||
|
||||
/**
|
||||
* Return mock settings for the given mock object.
|
||||
* @param mock the mock object
|
||||
* @return the mock creation settings
|
||||
*/
|
||||
public abstract MockCreationSettings<?> getMockSettings(Object mock);
|
||||
|
||||
/**
|
||||
* Return the mocking progress for the current thread.
|
||||
* @param mock the bean under test
|
||||
* @return the current mocking progress
|
||||
*/
|
||||
public abstract MockingProgress mockingProgress(Object mock);
|
||||
|
||||
/**
|
||||
* Set report matchers to the given storage.
|
||||
* @param storage the storage to use
|
||||
* @param matchers the matchers to set
|
||||
*/
|
||||
public abstract void reportMatchers(ArgumentMatcherStorage storage,
|
||||
List<LocalizedMatcher> matchers);
|
||||
|
||||
/**
|
||||
* Create a new {@link MockAwareVerificationMode} instance.
|
||||
* @param mock the source mock
|
||||
* @param mode the verification mode
|
||||
* @return a new {@link MockAwareVerificationMode} instance
|
||||
*/
|
||||
public abstract MockAwareVerificationMode createMockAwareVerificationMode(Object mock,
|
||||
VerificationMode mode);
|
||||
|
||||
/**
|
||||
* Return the {@link Answer} for a given {@link Answers} value.
|
||||
* @param answer the source answers
|
||||
* @return the answer
|
||||
*/
|
||||
public abstract Answer<Object> getAnswer(Answers answer);
|
||||
|
||||
/**
|
||||
* Factory to create the appropriate API version.
|
||||
* @return the API version
|
||||
*/
|
||||
private static MockitoApi createApi() {
|
||||
if (ClassUtils.isPresent("org.mockito.quality.MockitoHint", null)) {
|
||||
return new Mockito2Api();
|
||||
}
|
||||
return new Mockito1Api();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API for the running mockito version.
|
||||
* @return the API
|
||||
*/
|
||||
public static MockitoApi get() {
|
||||
return api;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link MockitoApi} for Mockito 1.0.
|
||||
*/
|
||||
private static class Mockito1Api extends MockitoApi {
|
||||
|
||||
@Override
|
||||
public MockCreationSettings<?> getMockSettings(Object mock) {
|
||||
return new MockUtil().getMockSettings(mock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockingProgress mockingProgress(Object mock) {
|
||||
MockUtil mockUtil = new MockUtil();
|
||||
InternalMockHandler<?> handler = mockUtil.getMockHandler(mock);
|
||||
InvocationContainer container = handler.getInvocationContainer();
|
||||
Field field = ReflectionUtils.findField(container.getClass(),
|
||||
"mockingProgress");
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return (MockingProgress) ReflectionUtils.getField(field, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportMatchers(ArgumentMatcherStorage storage,
|
||||
List<LocalizedMatcher> matchers) {
|
||||
for (LocalizedMatcher matcher : matchers) {
|
||||
storage.reportMatcher(matcher);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockAwareVerificationMode createMockAwareVerificationMode(Object mock,
|
||||
VerificationMode mode) {
|
||||
return new MockAwareVerificationMode(mock, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Answer<Object> getAnswer(Answers answer) {
|
||||
return answer.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link MockitoApi} for Mockito 2.0.
|
||||
*/
|
||||
private static class Mockito2Api extends MockitoApi {
|
||||
|
||||
private final Method getMockSettingsMethod;
|
||||
|
||||
private final Method mockingProgressMethod;
|
||||
|
||||
private final Method reportMatcherMethod;
|
||||
|
||||
private final Method getMatcherMethod;
|
||||
|
||||
private Constructor<MockAwareVerificationMode> mockAwareVerificationModeConstructor;
|
||||
|
||||
public Mockito2Api() {
|
||||
this.getMockSettingsMethod = ReflectionUtils.findMethod(MockUtil.class,
|
||||
"getMockSettings", Object.class);
|
||||
this.mockingProgressMethod = ReflectionUtils
|
||||
.findMethod(ThreadSafeMockingProgress.class, "mockingProgress");
|
||||
this.reportMatcherMethod = ReflectionUtils.findMethod(
|
||||
ArgumentMatcherStorage.class, "reportMatcher", ArgumentMatcher.class);
|
||||
this.getMatcherMethod = ReflectionUtils.findMethod(LocalizedMatcher.class,
|
||||
"getMatcher");
|
||||
this.mockAwareVerificationModeConstructor = ClassUtils
|
||||
.getConstructorIfAvailable(MockAwareVerificationMode.class,
|
||||
Object.class, VerificationMode.class, Set.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockCreationSettings<?> getMockSettings(Object mock) {
|
||||
return (MockCreationSettings<?>) ReflectionUtils
|
||||
.invokeMethod(this.getMockSettingsMethod, null, mock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockingProgress mockingProgress(Object mock) {
|
||||
return (MockingProgress) ReflectionUtils
|
||||
.invokeMethod(this.mockingProgressMethod, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportMatchers(ArgumentMatcherStorage storage,
|
||||
List<LocalizedMatcher> matchers) {
|
||||
for (LocalizedMatcher matcher : matchers) {
|
||||
ReflectionUtils.invokeMethod(this.reportMatcherMethod, storage,
|
||||
ReflectionUtils.invokeMethod(this.getMatcherMethod, matcher));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockAwareVerificationMode createMockAwareVerificationMode(Object mock,
|
||||
VerificationMode mode) {
|
||||
if (this.mockAwareVerificationModeConstructor != null) {
|
||||
// Later 2.0 releases include a listener set
|
||||
return BeanUtils.instantiateClass(
|
||||
this.mockAwareVerificationModeConstructor, mock, mode,
|
||||
Collections.emptySet());
|
||||
}
|
||||
return new MockAwareVerificationMode(mock, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Answer<Object> getAnswer(Answers answer) {
|
||||
return (Answer<Object>) ((Object) answer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* 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 java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.mockito.ArgumentMatcher;
|
||||
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.util.MockUtil;
|
||||
import org.mockito.mock.MockCreationSettings;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A facade for Mockito's {@link MockUtil} that hides API differences between Mockito 1
|
||||
* and 2.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
final class SpringBootMockUtil {
|
||||
|
||||
private static final MockUtilAdapter adapter;
|
||||
|
||||
static {
|
||||
if (ClassUtils.isPresent("org.mockito.quality.MockitoHint",
|
||||
SpringBootMockUtil.class.getClassLoader())) {
|
||||
adapter = new Mockito2MockUtilAdapter();
|
||||
}
|
||||
else {
|
||||
adapter = new Mockito1MockUtilAdapter();
|
||||
}
|
||||
}
|
||||
|
||||
private SpringBootMockUtil() {
|
||||
|
||||
}
|
||||
|
||||
static MockCreationSettings<?> getMockSettings(Object mock) {
|
||||
return adapter.getMockSettings(mock);
|
||||
}
|
||||
|
||||
static MockingProgress mockingProgress() {
|
||||
return adapter.mockingProgress();
|
||||
}
|
||||
|
||||
static void reportMatchers(ArgumentMatcherStorage storage,
|
||||
List<LocalizedMatcher> matchers) {
|
||||
adapter.reportMatchers(storage, matchers);
|
||||
}
|
||||
|
||||
private interface MockUtilAdapter {
|
||||
|
||||
MockCreationSettings<?> getMockSettings(Object mock);
|
||||
|
||||
MockingProgress mockingProgress();
|
||||
|
||||
void reportMatchers(ArgumentMatcherStorage storage,
|
||||
List<LocalizedMatcher> matchers);
|
||||
|
||||
}
|
||||
|
||||
private static class Mockito1MockUtilAdapter implements MockUtilAdapter {
|
||||
|
||||
private static final MockingProgress mockingProgress = new ThreadSafeMockingProgress();
|
||||
|
||||
@Override
|
||||
public MockCreationSettings<?> getMockSettings(Object mock) {
|
||||
return new MockUtil().getMockSettings(mock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockingProgress mockingProgress() {
|
||||
return mockingProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportMatchers(ArgumentMatcherStorage storage,
|
||||
List<LocalizedMatcher> matchers) {
|
||||
for (LocalizedMatcher matcher : matchers) {
|
||||
storage.reportMatcher(matcher);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class Mockito2MockUtilAdapter implements MockUtilAdapter {
|
||||
|
||||
private final Method getMockSettingsMethod = ReflectionUtils
|
||||
.findMethod(MockUtil.class, "getMockSettings", Object.class);
|
||||
|
||||
private final Method mockingProgressMethod = ReflectionUtils
|
||||
.findMethod(ThreadSafeMockingProgress.class, "mockingProgress");
|
||||
|
||||
private final Method reportMatcherMethod = ReflectionUtils.findMethod(
|
||||
ArgumentMatcherStorage.class, "reportMatcher", ArgumentMatcher.class);
|
||||
|
||||
private final Method getMatcherMethod = ReflectionUtils
|
||||
.findMethod(LocalizedMatcher.class, "getMatcher");
|
||||
|
||||
@Override
|
||||
public MockCreationSettings<?> getMockSettings(Object mock) {
|
||||
return (MockCreationSettings<?>) ReflectionUtils
|
||||
.invokeMethod(this.getMockSettingsMethod, null, mock);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockingProgress mockingProgress() {
|
||||
return (MockingProgress) ReflectionUtils
|
||||
.invokeMethod(this.mockingProgressMethod, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportMatchers(ArgumentMatcherStorage storage,
|
||||
List<LocalizedMatcher> matchers) {
|
||||
for (LocalizedMatcher matcher : matchers) {
|
||||
ReflectionUtils.invokeMethod(this.reportMatcherMethod, storage,
|
||||
ReflectionUtils.invokeMethod(this.getMatcherMethod, matcher));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -85,7 +85,7 @@ public class MockDefinitionTests {
|
|||
new Class<?>[] { ExampleExtraInterface.class },
|
||||
Answers.RETURNS_SMART_NULLS, true, MockReset.BEFORE, null);
|
||||
ExampleService mock = definition.createMock();
|
||||
MockCreationSettings<?> settings = SpringBootMockUtil.getMockSettings(mock);
|
||||
MockCreationSettings<?> settings = MockitoApi.get().getMockSettings(mock);
|
||||
assertThat(mock).isInstanceOf(ExampleService.class);
|
||||
assertThat(mock).isInstanceOf(ExampleExtraInterface.class);
|
||||
assertThat(settings.getMockName().toString()).isEqualTo("name");
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.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;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for compatibility with Mockito 2.5
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathOverrides("org.mockito:mockito-core:2.5.4")
|
||||
public class Mockito25Tests {
|
||||
|
||||
@Test
|
||||
public void resetMocksTestExecutionListenerTestsWithMockito2() {
|
||||
runTests(ResetMocksTestExecutionListenerTests.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spyBeanWithAopProxyTestsWithMockito2() {
|
||||
runTests(SpyBeanWithAopProxyTests.class);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -78,7 +78,7 @@ public class SpyDefinitionTests {
|
|||
SpyDefinition definition = new SpyDefinition("name", REAL_SERVICE_TYPE,
|
||||
MockReset.BEFORE, true, null);
|
||||
RealExampleService spy = definition.createSpy(new RealExampleService("hello"));
|
||||
MockCreationSettings<?> settings = SpringBootMockUtil.getMockSettings(spy);
|
||||
MockCreationSettings<?> settings = MockitoApi.get().getMockSettings(spy);
|
||||
assertThat(spy).isInstanceOf(ExampleService.class);
|
||||
assertThat(settings.getMockName().toString()).isEqualTo("name");
|
||||
assertThat(settings.getDefaultAnswer())
|
||||
|
|
Loading…
Reference in New Issue