Reinstate init of Mockito mocks in test execution listener
Closes gh-42708
This commit is contained in:
parent
2014176d46
commit
1b6b9efcb2
|
|
@ -16,18 +16,29 @@
|
|||
|
||||
package org.springframework.boot.test.mock.mockito;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.TestExecutionListener;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.FieldCallback;
|
||||
|
||||
/**
|
||||
* {@link TestExecutionListener} to enable {@link MockBean @MockBean} and
|
||||
* {@link SpyBean @SpyBean} support.
|
||||
* {@link SpyBean @SpyBean} support. Also triggers
|
||||
* {@link MockitoAnnotations#openMocks(Object)} when any Mockito annotations used,
|
||||
* primarily to allow {@link Captor @Captor} annotations.
|
||||
* <p>
|
||||
* To use the automatic reset support of {@code @MockBean} and {@code @SpyBean}, configure
|
||||
* {@link ResetMocksTestExecutionListener} as well.
|
||||
|
|
@ -37,13 +48,15 @@ import org.springframework.util.ReflectionUtils;
|
|||
* @author Moritz Halbritter
|
||||
* @since 1.4.2
|
||||
* @see ResetMocksTestExecutionListener
|
||||
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of
|
||||
* {@link org.springframework.test.context.bean.override.mockito.MockitoTestExecutionListener}
|
||||
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of Spring Framework's support for
|
||||
* {@link MockitoBean} and {@link MockitoSpyBean}.
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
@Deprecated(since = "3.4.0", forRemoval = true)
|
||||
public class MockitoTestExecutionListener extends AbstractTestExecutionListener {
|
||||
|
||||
private static final String MOCKS_ATTRIBUTE_NAME = MockitoTestExecutionListener.class.getName() + ".mocks";
|
||||
|
||||
@Override
|
||||
public final int getOrder() {
|
||||
return 1950;
|
||||
|
|
@ -51,6 +64,8 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
|
|||
|
||||
@Override
|
||||
public void prepareTestInstance(TestContext testContext) throws Exception {
|
||||
closeMocks(testContext);
|
||||
initMocks(testContext);
|
||||
injectFields(testContext);
|
||||
}
|
||||
|
||||
|
|
@ -58,10 +73,41 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
|
|||
public void beforeTestMethod(TestContext testContext) throws Exception {
|
||||
if (Boolean.TRUE.equals(
|
||||
testContext.getAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE))) {
|
||||
closeMocks(testContext);
|
||||
initMocks(testContext);
|
||||
reinjectFields(testContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||
closeMocks(testContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTestClass(TestContext testContext) throws Exception {
|
||||
closeMocks(testContext);
|
||||
}
|
||||
|
||||
private void initMocks(TestContext testContext) {
|
||||
if (hasMockitoAnnotations(testContext)) {
|
||||
testContext.setAttribute(MOCKS_ATTRIBUTE_NAME, MockitoAnnotations.openMocks(testContext.getTestInstance()));
|
||||
}
|
||||
}
|
||||
|
||||
private void closeMocks(TestContext testContext) throws Exception {
|
||||
Object mocks = testContext.getAttribute(MOCKS_ATTRIBUTE_NAME);
|
||||
if (mocks instanceof AutoCloseable closeable) {
|
||||
closeable.close();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasMockitoAnnotations(TestContext testContext) {
|
||||
MockitoAnnotationCollection collector = new MockitoAnnotationCollection();
|
||||
ReflectionUtils.doWithFields(testContext.getTestClass(), collector);
|
||||
return collector.hasAnnotations();
|
||||
}
|
||||
|
||||
private void injectFields(TestContext testContext) {
|
||||
postProcessFields(testContext, (mockitoField, postProcessor) -> postProcessor.inject(mockitoField.field,
|
||||
mockitoField.target, mockitoField.definition));
|
||||
|
|
@ -90,6 +136,28 @@ public class MockitoTestExecutionListener extends AbstractTestExecutionListener
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FieldCallback} to collect Mockito annotations.
|
||||
*/
|
||||
private static final class MockitoAnnotationCollection implements FieldCallback {
|
||||
|
||||
private final Set<Annotation> annotations = new LinkedHashSet<>();
|
||||
|
||||
@Override
|
||||
public void doWith(Field field) throws IllegalArgumentException {
|
||||
for (Annotation annotation : field.getDeclaredAnnotations()) {
|
||||
if (annotation.annotationType().getName().startsWith("org.mockito")) {
|
||||
this.annotations.add(annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasAnnotations() {
|
||||
return !this.annotations.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class MockitoField {
|
||||
|
||||
private final Field field;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.boot.test.context.nestedtests;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -40,7 +39,6 @@ import static org.mockito.Mockito.times;
|
|||
*/
|
||||
@SpringBootTest(classes = AppConfiguration.class)
|
||||
@Import(ActionPerformer.class)
|
||||
@Disabled("https://github.com/spring-projects/spring-framework/issues/33676")
|
||||
class InheritedNestedTestConfigurationTests {
|
||||
|
||||
@MockitoBean
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ import static org.mockito.BDDMockito.given;
|
|||
@SuppressWarnings("removal")
|
||||
@Deprecated(since = "3.4.0", forRemoval = true)
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@Disabled("https://github.com/spring-projects/spring-framework/issues/33690")
|
||||
class MockitoTestExecutionListenerIntegrationTests {
|
||||
|
||||
@Nested
|
||||
|
|
|
|||
|
|
@ -56,6 +56,14 @@ class MockitoTestExecutionListenerTests {
|
|||
@Mock
|
||||
private MockitoPostProcessor postProcessor;
|
||||
|
||||
@Test
|
||||
void prepareTestInstanceShouldInitMockitoAnnotations() throws Exception {
|
||||
WithMockitoAnnotations instance = new WithMockitoAnnotations();
|
||||
this.listener.prepareTestInstance(mockTestContext(instance));
|
||||
assertThat(instance.mock).isNotNull();
|
||||
assertThat(instance.captor).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void prepareTestInstanceShouldInjectMockBean() throws Exception {
|
||||
given(this.applicationContext.getBean(MockitoPostProcessor.class)).willReturn(this.postProcessor);
|
||||
|
|
|
|||
Loading…
Reference in New Issue