diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 3a0217bcf6..75dc0f272f 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -1,6 +1,4 @@ - - + 4.0.0 org.springframework.boot spring-boot-dependencies @@ -2563,4 +2561,4 @@ integration-test - + \ No newline at end of file diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockDefinition.java b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockDefinition.java index 07df1db3fa..24e6a08d8e 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockDefinition.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockDefinition.java @@ -24,7 +24,6 @@ import java.util.Set; import org.mockito.Answers; import org.mockito.MockSettings; import org.mockito.Mockito; -import org.mockito.stubbing.Answer; import org.springframework.core.ResolvableType; import org.springframework.core.style.ToStringCreator; @@ -149,19 +148,11 @@ class MockDefinition extends Definition { if (!this.extraInterfaces.isEmpty()) { settings.extraInterfaces(this.extraInterfaces.toArray(new Class[] {})); } - settings.defaultAnswer(getAnswer(this.answer)); + settings.defaultAnswer(MockitoApi.get().getAnswer(this.answer)); if (this.serializable) { settings.serializable(); } return (T) Mockito.mock(this.typeToMock.resolve(), settings); } - private Answer getAnswer(Answers answer) { - if (Answer.class.isInstance(answer)) { - // With Mockito 2.0 we can directly cast the answer - return (Answer) ((Object) answer); - } - return answer.get(); - } - } diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockReset.java b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockReset.java index 63eab8bce5..b4d6930733 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockReset.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockReset.java @@ -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) { diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoAopProxyTargetInterceptor.java b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoAopProxyTargetInterceptor.java index 115fa549cf..593b2d06a6 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoAopProxyTargetInterceptor.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoAopProxyTargetInterceptor.java @@ -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; @@ -88,10 +89,11 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor { private final Object monitor = new Object(); + private final MockingProgress progress = MockitoApi.get().mockingProgress(); + 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 +104,12 @@ 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 = SpringBootMockUtil.createMockAwareVerificationMode( + mode = MockitoApi.get().createMockAwareVerificationMode( target, mockAwareMode); } } @@ -118,11 +119,10 @@ class MockitoAopProxyTargetInterceptor implements MethodInterceptor { } private void resetVerificationStarted(VerificationMode mode) { - ArgumentMatcherStorage storage = SpringBootMockUtil.mockingProgress() - .getArgumentMatcherStorage(); + ArgumentMatcherStorage storage = this.progress.getArgumentMatcherStorage(); List matchers = storage.pullLocalizedMatchers(); - SpringBootMockUtil.mockingProgress().verificationStarted(mode); - SpringBootMockUtil.reportMatchers(storage, matchers); + MockitoApi.get().mockingProgress().verificationStarted(mode); + MockitoApi.get().reportMatchers(storage, matchers); } } diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoApi.java b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoApi.java new file mode 100644 index 0000000000..073ca7180a --- /dev/null +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/MockitoApi.java @@ -0,0 +1,240 @@ +/* + * 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.Method; +import java.util.Collections; +import java.util.List; + +import org.hamcrest.Matcher; +import org.mockito.Answers; +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.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.Assert; +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. + * @return the current mocking progress + */ + public abstract MockingProgress mockingProgress(); + + /** + * 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 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 getAnswer(Answers answer); + + /** + * Factory to create the appropriate API version. + * @return the API version + */ + private static MockitoApi createApi() { + if (!ClassUtils.isPresent("org.mockito.ReturnValues", + MockitoApi.class.getClassLoader())) { + 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 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 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 constructor = ClassUtils + .getConstructorIfAvailable(MockAwareVerificationMode.class, + Object.class, VerificationMode.class); + if (constructor == null) { + throw ex; + } + return BeanUtils.instantiateClass(constructor, mock, mode); + } + } + + @Override + public Answer getAnswer(Answers answer) { + return answer; + } + + } + + /** + * {@link MockitoApi} for Mockito 1.0. + */ + private static class Mockito1Api extends MockitoApi { + + private final MockUtil mockUtil; + + private final Method getMockSettingsMethod; + + private final MockingProgress mockingProgress; + + private Method reportMatcherMethod; + + private Constructor mockAwareVerificationModeConstructor; + + Mockito1Api() { + this.mockUtil = BeanUtils.instantiateClass(MockUtil.class); + this.getMockSettingsMethod = findMockSettingsMethod(); + this.mockingProgress = (MockingProgress) BeanUtils + .instantiateClass(ClassUtils.resolveClassName( + "org.mockito.internal.progress.ThreadSafeMockingProgress", + MockitoApi.class.getClassLoader())); + this.reportMatcherMethod = findReportMatcherMethod(); + this.mockAwareVerificationModeConstructor = findMockAwareVerificationModeConstructor(); + } + + private Method findMockSettingsMethod() { + Method method = ReflectionUtils.findMethod(MockUtil.class, "getMockSettings", + Object.class); + Assert.state(method != null, "Unable to find getMockSettings method"); + return method; + } + + private Method findReportMatcherMethod() { + Method method = ReflectionUtils.findMethod(ArgumentMatcherStorage.class, + "reportMatcher", Matcher.class); + Assert.state(method != null, "Unable to find reportMatcher method"); + return method; + } + + private Constructor findMockAwareVerificationModeConstructor() { + Constructor constructor = ClassUtils + .getConstructorIfAvailable(MockAwareVerificationMode.class, + Object.class, VerificationMode.class); + Assert.state(constructor != null, + "Unable to find MockAwareVerificationMode constructor"); + return constructor; + } + + @Override + public MockCreationSettings getMockSettings(Object mock) { + return (MockCreationSettings) ReflectionUtils + .invokeMethod(this.getMockSettingsMethod, this.mockUtil, mock); + } + + @Override + public MockingProgress mockingProgress() { + return this.mockingProgress; + } + + @Override + public void reportMatchers(ArgumentMatcherStorage storage, + List matchers) { + for (LocalizedMatcher matcher : matchers) { + ReflectionUtils.invokeMethod(this.reportMatcherMethod, storage, matcher); + } + } + + @Override + public MockAwareVerificationMode createMockAwareVerificationMode(Object mock, + VerificationMode mode) { + return BeanUtils.instantiateClass(this.mockAwareVerificationModeConstructor, + mock, mode); + } + + @Override + @SuppressWarnings("deprecation") + public Answer getAnswer(Answers answer) { + return answer.get(); + } + + } + +} diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/SpringBootMockUtil.java b/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/SpringBootMockUtil.java deleted file mode 100644 index 679190747e..0000000000 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/mock/mockito/SpringBootMockUtil.java +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2012-2017 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.Method; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import org.hamcrest.Matcher; -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.internal.verification.MockAwareVerificationMode; -import org.mockito.mock.MockCreationSettings; -import org.mockito.verification.VerificationMode; - -import org.springframework.beans.BeanUtils; -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 - * @author Stephane Nicoll - */ -final class SpringBootMockUtil { - - private static final MockUtilAdapter adapter; - - static { - if (ClassUtils.isPresent("org.mockito.ReturnValues", - SpringBootMockUtil.class.getClassLoader())) { - adapter = new Mockito1MockUtilAdapter(); - } - else { - adapter = new Mockito2MockUtilAdapter(); - } - } - - private SpringBootMockUtil() { - - } - - static MockCreationSettings getMockSettings(Object mock) { - return adapter.getMockSettings(mock); - } - - static MockingProgress mockingProgress() { - return adapter.mockingProgress(); - } - - static void reportMatchers(ArgumentMatcherStorage storage, - List matchers) { - adapter.reportMatchers(storage, matchers); - } - - static MockAwareVerificationMode createMockAwareVerificationMode(Object mock, - VerificationMode mode) { - return adapter.createMockAwareVerificationMode(mock, mode); - } - - private interface MockUtilAdapter { - - MockCreationSettings getMockSettings(Object mock); - - MockingProgress mockingProgress(); - - void reportMatchers(ArgumentMatcherStorage storage, - List matchers); - - MockAwareVerificationMode createMockAwareVerificationMode(Object mock, - VerificationMode mode); - - } - - private static class Mockito1MockUtilAdapter implements MockUtilAdapter { - - private final MockUtil mockUtil = BeanUtils.instantiateClass(MockUtil.class); - - private final Method getMockSettingsMethod = ReflectionUtils - .findMethod(MockUtil.class, "getMockSettings", Object.class); - - private static final MockingProgress mockingProgress = createThreadSafeMockingProgress(); - - private final Method reportMatcherMethod = ReflectionUtils - .findMethod(ArgumentMatcherStorage.class, "reportMatcher", Matcher.class); - - private static final Constructor mockAwareVerificationModeConstructor = getMockAwareVerificationModeConstructor(); - - private static MockingProgress createThreadSafeMockingProgress() { - try { - Class target = ClassUtils.forName( - "org.mockito.internal.progress.ThreadSafeMockingProgress", - SpringBootMockUtil.class.getClassLoader()); - return (MockingProgress) BeanUtils.instantiateClass(target); - } - catch (ClassNotFoundException ex) { - throw new IllegalStateException(ex); - } - } - - private static Constructor getMockAwareVerificationModeConstructor() { - try { - return MockAwareVerificationMode.class.getConstructor(Object.class, - VerificationMode.class); - } - catch (NoSuchMethodException ex) { - throw new IllegalStateException(ex); - } - } - - @Override - public MockCreationSettings getMockSettings(Object mock) { - return (MockCreationSettings) ReflectionUtils - .invokeMethod(this.getMockSettingsMethod, this.mockUtil, mock); - } - - @Override - public MockingProgress mockingProgress() { - return mockingProgress; - } - - @Override - public void reportMatchers(ArgumentMatcherStorage storage, - List matchers) { - for (LocalizedMatcher matcher : matchers) { - ReflectionUtils.invokeMethod(this.reportMatcherMethod, storage, matcher); - } - } - - @Override - public MockAwareVerificationMode createMockAwareVerificationMode(Object mock, - VerificationMode mode) { - return BeanUtils.instantiateClass(mockAwareVerificationModeConstructor, mock, - mode); - } - } - - private static class Mockito2MockUtilAdapter implements MockUtilAdapter { - - private static final Constructor mockAwareVerificationModeConstructor; - private static final boolean mockAwareVerificationModeLegacy; - - static { - Constructor c = getMockAwareVerificationModeConstructor(); - if (c != null) { - mockAwareVerificationModeConstructor = c; - mockAwareVerificationModeLegacy = false; - } - else { - mockAwareVerificationModeConstructor = getMockAwareVerificationModeLegacyConstructor(); - mockAwareVerificationModeLegacy = true; - } - } - - @Override - public MockCreationSettings getMockSettings(Object mock) { - return MockUtil.getMockSettings(mock); - } - - @Override - public MockingProgress mockingProgress() { - return ThreadSafeMockingProgress.mockingProgress(); - } - - @Override - public void reportMatchers(ArgumentMatcherStorage storage, - List matchers) { - for (LocalizedMatcher matcher : matchers) { - storage.reportMatcher(matcher.getMatcher()); - } - } - - @Override - public MockAwareVerificationMode createMockAwareVerificationMode(Object mock, - VerificationMode mode) { - if (mockAwareVerificationModeLegacy) { - return BeanUtils.instantiateClass(mockAwareVerificationModeConstructor, - mock, mode); - } - else { - return BeanUtils.instantiateClass(mockAwareVerificationModeConstructor, - mock, mode, Collections.emptySet()); - } - } - - private static Constructor getMockAwareVerificationModeLegacyConstructor() { - try { - return MockAwareVerificationMode.class.getConstructor(Object.class, - VerificationMode.class); - } - catch (NoSuchMethodException ex) { - return null; - } - } - - private static Constructor getMockAwareVerificationModeConstructor() { - try { - return MockAwareVerificationMode.class.getConstructor(Object.class, - VerificationMode.class, Set.class); - } - catch (NoSuchMethodException ex) { - return null; - } - } - - } - -} diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockDefinitionTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockDefinitionTests.java index cb8eaa8fea..d50a5f0225 100644 --- a/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockDefinitionTests.java +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/MockDefinitionTests.java @@ -85,12 +85,11 @@ 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"); - assertThat(settings.getDefaultAnswer()) - .isEqualTo(Answers.RETURNS_SMART_NULLS.get()); + assertThat(settings.getDefaultAnswer()).isEqualTo(Answers.RETURNS_SMART_NULLS); assertThat(settings.isSerializable()).isTrue(); assertThat(MockReset.get(mock)).isEqualTo(MockReset.BEFORE); } diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/SpyDefinitionTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/SpyDefinitionTests.java index 47b800bbd2..73ecac501a 100644 --- a/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/SpyDefinitionTests.java +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/mock/mockito/SpyDefinitionTests.java @@ -78,11 +78,10 @@ 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()) - .isEqualTo(Answers.CALLS_REAL_METHODS.get()); + assertThat(settings.getDefaultAnswer()).isEqualTo(Answers.CALLS_REAL_METHODS); assertThat(MockReset.get(spy)).isEqualTo(MockReset.BEFORE); }