Register EventPublishingTestExecutionListener by default (round 2)
This commit registers the EventPublishingTestExecutionListener as a default TestExecutionListener with an order of 10,000. This registers the EventPublishingTestExecutionListener as the last listener provided by the Spring Framework. With EventPublishingTestExecutionListener registered with an order of 10,000, it is effectively wrapped by all other Spring listeners, including support for @DirtiesContext and test-managed transactions. Furthermore, this commit revises the implementation of EventPublishingTestExecutionListener to take advantage of the new TestContext#hasApplicationContext() support which allows the EventPublishingTestExecutionListener to publish events only if the test's ApplicationContext is currently available. This avoids undesirable side-effects such as eager loading of the ApplicationContext before it is needed or re-loading of the ApplicationContext after it has been intentionally closed. Closes gh-18490
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -24,6 +24,7 @@ import org.junit.Test;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
||||
import org.springframework.test.context.event.EventPublishingTestExecutionListener;
|
||||
import org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
@@ -57,7 +58,7 @@ public class TestExecutionListenersTests {
|
||||
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
|
||||
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
||||
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
|
||||
SqlScriptsTestExecutionListener.class);
|
||||
SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class);
|
||||
assertRegisteredListeners(DefaultListenersTestCase.class, expected);
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ public class TestExecutionListenersTests {
|
||||
List<Class<?>> expected = asList(QuuxTestExecutionListener.class, ServletTestExecutionListener.class,
|
||||
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
||||
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
|
||||
SqlScriptsTestExecutionListener.class);
|
||||
SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class);
|
||||
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerPrependedTestCase.class, expected);
|
||||
}
|
||||
|
||||
@@ -81,7 +82,8 @@ public class TestExecutionListenersTests {
|
||||
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
|
||||
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
||||
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
|
||||
SqlScriptsTestExecutionListener.class, BazTestExecutionListener.class);
|
||||
SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class,
|
||||
BazTestExecutionListener.class);
|
||||
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerAppendedTestCase.class, expected);
|
||||
}
|
||||
|
||||
@@ -93,7 +95,8 @@ public class TestExecutionListenersTests {
|
||||
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
|
||||
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
||||
BarTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
|
||||
TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class);
|
||||
TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class,
|
||||
EventPublishingTestExecutionListener.class);
|
||||
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerInsertedTestCase.class, expected);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -22,7 +22,6 @@ import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -30,7 +29,11 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener;
|
||||
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.test.context.cache.ContextCacheTestUtils.*;
|
||||
@@ -44,7 +47,6 @@ import static org.springframework.test.context.junit4.JUnitTestingUtils.*;
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class ClassLevelDirtiesContextTests {
|
||||
|
||||
private static final AtomicInteger cacheHits = new AtomicInteger(0);
|
||||
@@ -146,6 +148,14 @@ public class ClassLevelDirtiesContextTests {
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration
|
||||
// Ensure that we do not include the EventPublishingTestExecutionListener
|
||||
// since it will access the ApplicationContext for each method in the
|
||||
// TestExecutionListener API, thus distorting our cache hit/miss results.
|
||||
@TestExecutionListeners({
|
||||
DirtiesContextBeforeModesTestExecutionListener.class,
|
||||
DependencyInjectionTestExecutionListener.class,
|
||||
DirtiesContextTestExecutionListener.class
|
||||
})
|
||||
static abstract class BaseTestCase {
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
@@ -22,12 +22,15 @@ import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener;
|
||||
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.test.context.cache.ContextCacheTestUtils.*;
|
||||
@@ -37,7 +40,6 @@ import static org.springframework.test.context.junit4.JUnitTestingUtils.*;
|
||||
* @author Sam Brannen
|
||||
* @since 4.3
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class DirtiesContextInterfaceTests {
|
||||
|
||||
private static final AtomicInteger cacheHits = new AtomicInteger(0);
|
||||
@@ -72,6 +74,14 @@ public class DirtiesContextInterfaceTests {
|
||||
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
// Ensure that we do not include the EventPublishingTestExecutionListener
|
||||
// since it will access the ApplicationContext for each method in the
|
||||
// TestExecutionListener API, thus distorting our cache hit/miss results.
|
||||
@TestExecutionListeners({
|
||||
DirtiesContextBeforeModesTestExecutionListener.class,
|
||||
DependencyInjectionTestExecutionListener.class,
|
||||
DirtiesContextTestExecutionListener.class
|
||||
})
|
||||
public static class ClassLevelDirtiesContextWithCleanMethodsAndDefaultModeTestCase
|
||||
implements DirtiesContextTestInterface {
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.TestContextManager;
|
||||
import org.springframework.test.context.TestExecutionListener;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.event.annotation.AfterTestClass;
|
||||
import org.springframework.test.context.event.annotation.AfterTestExecution;
|
||||
import org.springframework.test.context.event.annotation.AfterTestMethod;
|
||||
@@ -193,7 +192,6 @@ public class EventPublishingTestExecutionListenerIntegrationTests {
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = TestEventListenerConfiguration.class)
|
||||
@TestExecutionListeners(EventPublishingTestExecutionListener.class)
|
||||
public static class ExampleTestCase {
|
||||
|
||||
@Traceable
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
|
||||
package org.springframework.test.context.event;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -26,16 +31,20 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.test.context.TestContext;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.only;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link EventPublishingTestExecutionListener}.
|
||||
*
|
||||
* @author Frank Scheffler
|
||||
* @author Sam Brannen
|
||||
* @since 5.2
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@@ -49,53 +58,97 @@ public class EventPublishingTestExecutionListenerTests {
|
||||
@Captor
|
||||
private ArgumentCaptor<TestContextEvent> testExecutionEvent;
|
||||
|
||||
@Rule
|
||||
public final TestName testName = new TestName();
|
||||
|
||||
|
||||
@Before
|
||||
public void configureMock() {
|
||||
if (testName.getMethodName().startsWith("publish")) {
|
||||
when(testContext.hasApplicationContext()).thenReturn(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishBeforeTestClassEvent() {
|
||||
listener.beforeTestClass(testContext);
|
||||
assertEvent(BeforeTestClassEvent.class);
|
||||
assertEvent(BeforeTestClassEvent.class, listener::beforeTestClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishPrepareTestInstanceEvent() {
|
||||
listener.prepareTestInstance(testContext);
|
||||
assertEvent(PrepareTestInstanceEvent.class);
|
||||
assertEvent(PrepareTestInstanceEvent.class, listener::prepareTestInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishBeforeTestMethodEvent() {
|
||||
listener.beforeTestMethod(testContext);
|
||||
assertEvent(BeforeTestMethodEvent.class);
|
||||
assertEvent(BeforeTestMethodEvent.class, listener::beforeTestMethod);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishBeforeTestExecutionEvent() {
|
||||
listener.beforeTestExecution(testContext);
|
||||
assertEvent(BeforeTestExecutionEvent.class);
|
||||
assertEvent(BeforeTestExecutionEvent.class, listener::beforeTestExecution);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishAfterTestExecutionEvent() {
|
||||
listener.afterTestExecution(testContext);
|
||||
assertEvent(AfterTestExecutionEvent.class);
|
||||
assertEvent(AfterTestExecutionEvent.class, listener::afterTestExecution);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishAfterTestMethodEvent() {
|
||||
listener.afterTestMethod(testContext);
|
||||
assertEvent(AfterTestMethodEvent.class);
|
||||
assertEvent(AfterTestMethodEvent.class, listener::afterTestMethod);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishAfterTestClassEvent() {
|
||||
listener.afterTestClass(testContext);
|
||||
assertEvent(AfterTestClassEvent.class);
|
||||
assertEvent(AfterTestClassEvent.class, listener::afterTestClass);
|
||||
}
|
||||
|
||||
private void assertEvent(Class<? extends TestContextEvent> eventClass) {
|
||||
private void assertEvent(Class<? extends TestContextEvent> eventClass, Consumer<TestContext> callback) {
|
||||
callback.accept(testContext);
|
||||
verify(testContext.getApplicationContext(), only()).publishEvent(testExecutionEvent.capture());
|
||||
assertThat(testExecutionEvent.getValue(), instanceOf(eventClass));
|
||||
assertThat(testExecutionEvent.getValue().getSource(), equalTo(testContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotPublishBeforeTestClassEventIfApplicationContextHasNotBeenLoaded() {
|
||||
assertNoEvent(listener::beforeTestClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotPublishPrepareTestInstanceEventIfApplicationContextHasNotBeenLoaded() {
|
||||
assertNoEvent(listener::prepareTestInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotPublishBeforeTestMethodEventIfApplicationContextHasNotBeenLoaded() {
|
||||
assertNoEvent(listener::beforeTestMethod);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotPublishBeforeTestExecutionEventIfApplicationContextHasNotBeenLoaded() {
|
||||
assertNoEvent(listener::beforeTestExecution);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotPublishAfterTestExecutionEventIfApplicationContextHasNotBeenLoaded() {
|
||||
assertNoEvent(listener::afterTestExecution);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotPublishAfterTestMethodEventIfApplicationContextHasNotBeenLoaded() {
|
||||
assertNoEvent(listener::afterTestMethod);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotPublishAfterTestClassEventIfApplicationContextHasNotBeenLoaded() {
|
||||
assertNoEvent(listener::afterTestClass);
|
||||
}
|
||||
|
||||
private void assertNoEvent(Consumer<TestContext> callback) {
|
||||
callback.accept(testContext);
|
||||
verify(testContext.getApplicationContext(), never()).publishEvent(any());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user