Extract common logic into AbstractMockitoTestExecutionListener
This commit is contained in:
@@ -22,28 +22,45 @@ import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Utility class that detects {@code org.mockito} annotations as well as the
|
||||
* annotations in this package (like {@link MockitoBeanSettings @MockitoBeanSettings}).
|
||||
* Abstract base class for {@code TestExecutionListener} implementations involving
|
||||
* Mockito.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Sam Brannen
|
||||
* @author Simon Baslé
|
||||
* @since 6.2
|
||||
*/
|
||||
abstract class MockitoAnnotationDetector {
|
||||
abstract class AbstractMockitoTestExecutionListener extends AbstractTestExecutionListener {
|
||||
|
||||
private static final String MOCKITO_BEAN_PACKAGE = MockitoBeanSettings.class.getPackageName();
|
||||
static final boolean mockitoPresent = ClassUtils.isPresent("org.mockito.Mockito",
|
||||
AbstractMockitoTestExecutionListener.class.getClassLoader());
|
||||
|
||||
private static final String SPRING_MOCKITO_PACKAGE = "org.springframework.test.context.bean.override.mockito";
|
||||
|
||||
private static final String ORG_MOCKITO_PACKAGE = "org.mockito";
|
||||
|
||||
private static final Predicate<Annotation> isMockitoAnnotation = annotation -> {
|
||||
String packageName = annotation.annotationType().getPackageName();
|
||||
return (packageName.startsWith(MOCKITO_BEAN_PACKAGE) ||
|
||||
return (packageName.startsWith(SPRING_MOCKITO_PACKAGE) ||
|
||||
packageName.startsWith(ORG_MOCKITO_PACKAGE));
|
||||
};
|
||||
|
||||
static boolean hasMockitoAnnotations(Class<?> testClass) {
|
||||
|
||||
/**
|
||||
* Determine if the test class for the supplied {@linkplain TestContext
|
||||
* test context} uses {@code org.mockito} annotations or any of the annotations
|
||||
* in this package (such as {@link MockitoBeanSettings @MockitoBeanSettings}).
|
||||
*/
|
||||
static boolean hasMockitoAnnotations(TestContext testContext) {
|
||||
return hasMockitoAnnotations(testContext.getTestClass());
|
||||
}
|
||||
|
||||
private static boolean hasMockitoAnnotations(Class<?> testClass) {
|
||||
if (isAnnotated(testClass)) {
|
||||
return true;
|
||||
}
|
||||
@@ -53,9 +70,10 @@ abstract class MockitoAnnotationDetector {
|
||||
// previous invocation of isAnnotated(testClass) only finds annotations declared directly
|
||||
// on the test class. So, we'll likely need a completely different approach that combines
|
||||
// the "test class/interface is annotated?" and "field is annotated?" checks in a single
|
||||
// search algorithm.
|
||||
// search algorithm, and we'll also need to support @Nested class hierarchies.
|
||||
AtomicBoolean found = new AtomicBoolean();
|
||||
ReflectionUtils.doWithFields(testClass, field -> found.set(true), MockitoAnnotationDetector::isAnnotated);
|
||||
ReflectionUtils.doWithFields(testClass,
|
||||
field -> found.set(true), AbstractMockitoTestExecutionListener::isAnnotated);
|
||||
return found.get();
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
|
||||
/**
|
||||
* {@code TestExecutionListener} that resets any mock beans that have been marked
|
||||
@@ -45,7 +44,7 @@ import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
* @see MockitoBean @MockitoBean
|
||||
* @see MockitoSpyBean @MockitoSpyBean
|
||||
*/
|
||||
public class MockitoResetTestExecutionListener extends AbstractTestExecutionListener {
|
||||
public class MockitoResetTestExecutionListener extends AbstractMockitoTestExecutionListener {
|
||||
|
||||
/**
|
||||
* Executes before {@link org.springframework.test.context.bean.override.BeanOverrideTestExecutionListener}.
|
||||
@@ -56,17 +55,15 @@ public class MockitoResetTestExecutionListener extends AbstractTestExecutionList
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTestMethod(TestContext testContext) throws Exception {
|
||||
Class<?> testClass = testContext.getTestClass();
|
||||
if (MockitoTestExecutionListener.mockitoPresent && MockitoAnnotationDetector.hasMockitoAnnotations(testClass)) {
|
||||
public void beforeTestMethod(TestContext testContext) {
|
||||
if (mockitoPresent && hasMockitoAnnotations(testContext)) {
|
||||
resetMocks(testContext.getApplicationContext(), MockReset.BEFORE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||
Class<?> testClass = testContext.getTestClass();
|
||||
if (MockitoTestExecutionListener.mockitoPresent && MockitoAnnotationDetector.hasMockitoAnnotations(testClass)) {
|
||||
public void afterTestMethod(TestContext testContext) {
|
||||
if (mockitoPresent && hasMockitoAnnotations(testContext)) {
|
||||
resetMocks(testContext.getApplicationContext(), MockReset.AFTER);
|
||||
}
|
||||
}
|
||||
@@ -114,7 +111,7 @@ public class MockitoResetTestExecutionListener extends AbstractTestExecutionList
|
||||
return beanFactory.getSingleton(beanName);
|
||||
}
|
||||
|
||||
private static boolean isStandardBeanOrSingletonFactoryBean(ConfigurableListableBeanFactory beanFactory, String beanName) {
|
||||
private static boolean isStandardBeanOrSingletonFactoryBean(BeanFactory beanFactory, String beanName) {
|
||||
String factoryBeanName = BeanFactory.FACTORY_BEAN_PREFIX + beanName;
|
||||
if (beanFactory.containsBean(factoryBeanName)) {
|
||||
FactoryBean<?> factoryBean = (FactoryBean<?>) beanFactory.getBean(factoryBeanName);
|
||||
|
||||
@@ -22,9 +22,7 @@ import org.mockito.quality.Strictness;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@code TestExecutionListener} that enables {@link MockitoBean @MockitoBean}
|
||||
@@ -49,12 +47,10 @@ import org.springframework.util.ClassUtils;
|
||||
* @see MockitoBean @MockitoBean
|
||||
* @see MockitoSpyBean @MockitoSpyBean
|
||||
*/
|
||||
public class MockitoTestExecutionListener extends AbstractTestExecutionListener {
|
||||
public class MockitoTestExecutionListener extends AbstractMockitoTestExecutionListener {
|
||||
|
||||
private static final String MOCKITO_SESSION_ATTRIBUTE_NAME = MockitoTestExecutionListener.class.getName() + ".mockitoSession";
|
||||
|
||||
static final boolean mockitoPresent = ClassUtils.isPresent("org.mockito.Mockito",
|
||||
MockitoTestExecutionListener.class.getClassLoader());
|
||||
private static final String MOCKITO_SESSION_ATTRIBUTE_NAME =
|
||||
MockitoTestExecutionListener.class.getName() + ".mockitoSession";
|
||||
|
||||
|
||||
/**
|
||||
@@ -66,7 +62,7 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareTestInstance(TestContext testContext) throws Exception {
|
||||
public void prepareTestInstance(TestContext testContext) {
|
||||
if (mockitoPresent) {
|
||||
closeMocks(testContext);
|
||||
initMocks(testContext);
|
||||
@@ -74,7 +70,7 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTestMethod(TestContext testContext) throws Exception {
|
||||
public void beforeTestMethod(TestContext testContext) {
|
||||
if (mockitoPresent && Boolean.TRUE.equals(
|
||||
testContext.getAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE))) {
|
||||
closeMocks(testContext);
|
||||
@@ -83,22 +79,22 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||
public void afterTestMethod(TestContext testContext) {
|
||||
if (mockitoPresent) {
|
||||
closeMocks(testContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestClass(TestContext testContext) throws Exception {
|
||||
public void afterTestClass(TestContext testContext) {
|
||||
if (mockitoPresent) {
|
||||
closeMocks(testContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initMocks(TestContext testContext) {
|
||||
Class<?> testClass = testContext.getTestClass();
|
||||
if (MockitoAnnotationDetector.hasMockitoAnnotations(testClass)) {
|
||||
if (hasMockitoAnnotations(testContext)) {
|
||||
Class<?> testClass = testContext.getTestClass();
|
||||
Object testInstance = testContext.getTestInstance();
|
||||
MockitoBeanSettings annotation = AnnotationUtils.findAnnotation(testClass, MockitoBeanSettings.class);
|
||||
Strictness strictness = (annotation != null ? annotation.value() : Strictness.STRICT_STUBS);
|
||||
@@ -113,9 +109,8 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
|
||||
.startMocking();
|
||||
}
|
||||
|
||||
private static void closeMocks(TestContext testContext) throws Exception {
|
||||
Object mocks = testContext.getAttribute(MOCKITO_SESSION_ATTRIBUTE_NAME);
|
||||
if (mocks instanceof MockitoSession session) {
|
||||
private static void closeMocks(TestContext testContext) {
|
||||
if (testContext.getAttribute(MOCKITO_SESSION_ATTRIBUTE_NAME) instanceof MockitoSession session) {
|
||||
session.finishMocking();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user