Skip to content

Commit 353e092

Browse files
committed
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
1 parent c3d0459 commit 353e092

File tree

9 files changed

+148
-71
lines changed

9 files changed

+148
-71
lines changed

spring-test/src/main/java/org/springframework/test/context/TestExecutionListener.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@
4444
* <p>Spring provides the following out-of-the-box implementations (all of
4545
* which implement {@code Ordered}):
4646
* <ul>
47-
* <li>{@link org.springframework.test.context.event.EventPublishingTestExecutionListener
48-
* EventPublishingTestExecutionListener} (not registered by default)</li>
4947
* <li>{@link org.springframework.test.context.web.ServletTestExecutionListener
5048
* ServletTestExecutionListener}</li>
5149
* <li>{@link org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener
@@ -58,6 +56,8 @@
5856
* TransactionalTestExecutionListener}</li>
5957
* <li>{@link org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener
6058
* SqlScriptsTestExecutionListener}</li>
59+
* <li>{@link org.springframework.test.context.event.EventPublishingTestExecutionListener
60+
* EventPublishingTestExecutionListener}</li>
6161
* </ul>
6262
*
6363
* @author Sam Brannen

spring-test/src/main/java/org/springframework/test/context/event/EventPublishingTestExecutionListener.java

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@
1616

1717
package org.springframework.test.context.event;
1818

19-
import org.springframework.core.Ordered;
19+
import java.util.function.Function;
20+
2021
import org.springframework.test.context.TestContext;
2122
import org.springframework.test.context.TestExecutionListener;
2223
import org.springframework.test.context.support.AbstractTestExecutionListener;
2324

2425
/**
2526
* {@link org.springframework.test.context.TestExecutionListener TestExecutionListener}
26-
* that publishes test execution events to a Spring test
27-
* {@link org.springframework.context.ApplicationContext ApplicationContext}.
27+
* that publishes test execution events to the
28+
* {@link org.springframework.context.ApplicationContext ApplicationContext}
29+
* for the currently executing test. Events are only published if the
30+
* {@code ApplicationContext} {@linkplain TestContext#hasApplicationContext()
31+
* has already been loaded}.
2832
*
2933
* <h3>Supported Events</h3>
3034
* <ul>
@@ -61,16 +65,8 @@
6165
* support. For further details, consult the class-level Javadoc for
6266
* {@link org.springframework.context.event.EventListener @EventListener}.
6367
*
64-
* <h3>Listener Registration</h3>
65-
* <p>Note that this {@code TestExecutionListener} is not registered by default,
66-
* but it may be registered for a given test class via
67-
* {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}
68-
* or globally via the {@link org.springframework.core.io.support.SpringFactoriesLoader
69-
* SpringFactoriesLoader} mechanism (consult the Javadoc and Spring reference manual for
70-
* details).
71-
*
72-
* @author Frank Scheffler
7368
* @author Sam Brannen
69+
* @author Frank Scheffler
7470
* @since 5.2
7571
* @see org.springframework.test.context.event.annotation.BeforeTestClass @BeforeTestClass
7672
* @see org.springframework.test.context.event.annotation.PrepareTestInstance @PrepareTestInstance
@@ -83,74 +79,80 @@
8379
public class EventPublishingTestExecutionListener extends AbstractTestExecutionListener {
8480

8581
/**
86-
* Returns {@link Ordered#HIGHEST_PRECEDENCE}.
82+
* Returns {@code 10000}.
8783
*/
8884
@Override
89-
public int getOrder() {
90-
return Ordered.HIGHEST_PRECEDENCE;
85+
public final int getOrder() {
86+
return 10_000;
9187
}
9288

9389
/**
94-
* Publishes a {@link BeforeTestClassEvent} to the {@code ApplicationContext}
90+
* Publish a {@link BeforeTestClassEvent} to the {@code ApplicationContext}
9591
* for the supplied {@link TestContext}.
9692
*/
9793
@Override
9894
public void beforeTestClass(TestContext testContext) {
99-
testContext.getApplicationContext().publishEvent(new BeforeTestClassEvent(testContext));
95+
publishEvent(testContext, BeforeTestClassEvent::new);
10096
}
10197

10298
/**
103-
* Publishes a {@link PrepareTestInstanceEvent} to the {@code ApplicationContext}
99+
* Publish a {@link PrepareTestInstanceEvent} to the {@code ApplicationContext}
104100
* for the supplied {@link TestContext}.
105101
*/
106102
@Override
107103
public void prepareTestInstance(TestContext testContext) {
108-
testContext.getApplicationContext().publishEvent(new PrepareTestInstanceEvent(testContext));
104+
publishEvent(testContext, PrepareTestInstanceEvent::new);
109105
}
110106

111107
/**
112-
* Publishes a {@link BeforeTestMethodEvent} to the {@code ApplicationContext}
108+
* Publish a {@link BeforeTestMethodEvent} to the {@code ApplicationContext}
113109
* for the supplied {@link TestContext}.
114110
*/
115111
@Override
116112
public void beforeTestMethod(TestContext testContext) {
117-
testContext.getApplicationContext().publishEvent(new BeforeTestMethodEvent(testContext));
113+
publishEvent(testContext, BeforeTestMethodEvent::new);
118114
}
119115

120116
/**
121-
* Publishes a {@link BeforeTestExecutionEvent} to the {@code ApplicationContext}
117+
* Publish a {@link BeforeTestExecutionEvent} to the {@code ApplicationContext}
122118
* for the supplied {@link TestContext}.
123119
*/
124120
@Override
125121
public void beforeTestExecution(TestContext testContext) {
126-
testContext.getApplicationContext().publishEvent(new BeforeTestExecutionEvent(testContext));
122+
publishEvent(testContext, BeforeTestExecutionEvent::new);
127123
}
128124

129125
/**
130-
* Publishes an {@link AfterTestExecutionEvent} to the {@code ApplicationContext}
126+
* Publish an {@link AfterTestExecutionEvent} to the {@code ApplicationContext}
131127
* for the supplied {@link TestContext}.
132128
*/
133129
@Override
134130
public void afterTestExecution(TestContext testContext) {
135-
testContext.getApplicationContext().publishEvent(new AfterTestExecutionEvent(testContext));
131+
publishEvent(testContext, AfterTestExecutionEvent::new);
136132
}
137133

138134
/**
139-
* Publishes an {@link AfterTestMethodEvent} to the {@code ApplicationContext}
135+
* Publish an {@link AfterTestMethodEvent} to the {@code ApplicationContext}
140136
* for the supplied {@link TestContext}.
141137
*/
142138
@Override
143139
public void afterTestMethod(TestContext testContext) {
144-
testContext.getApplicationContext().publishEvent(new AfterTestMethodEvent(testContext));
140+
publishEvent(testContext, AfterTestMethodEvent::new);
145141
}
146142

147143
/**
148-
* Publishes an {@link AfterTestClassEvent} to the {@code ApplicationContext}
144+
* Publish an {@link AfterTestClassEvent} to the {@code ApplicationContext}
149145
* for the supplied {@link TestContext}.
150146
*/
151147
@Override
152148
public void afterTestClass(TestContext testContext) {
153-
testContext.getApplicationContext().publishEvent(new AfterTestClassEvent(testContext));
149+
publishEvent(testContext, AfterTestClassEvent::new);
150+
}
151+
152+
private void publishEvent(TestContext testContext, Function<TestContext, TestContextEvent> eventFactory) {
153+
if (testContext.hasApplicationContext()) {
154+
testContext.getApplicationContext().publishEvent(eventFactory.apply(testContext));
155+
}
154156
}
155157

156158
}

spring-test/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ org.springframework.test.context.TestExecutionListener = \
66
org.springframework.test.context.support.DependencyInjectionTestExecutionListener,\
77
org.springframework.test.context.support.DirtiesContextTestExecutionListener,\
88
org.springframework.test.context.transaction.TransactionalTestExecutionListener,\
9-
org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener
9+
org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener,\
10+
org.springframework.test.context.event.EventPublishingTestExecutionListener
1011

1112
# Default ContextCustomizerFactory implementations for the Spring TestContext Framework
1213
#

spring-test/src/test/java/org/springframework/test/context/TestExecutionListenersTests.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424

2525
import org.springframework.core.Ordered;
2626
import org.springframework.core.annotation.AnnotationConfigurationException;
27+
import org.springframework.test.context.event.EventPublishingTestExecutionListener;
2728
import org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener;
2829
import org.springframework.test.context.support.AbstractTestExecutionListener;
2930
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
@@ -57,7 +58,7 @@ public void defaultListeners() {
5758
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
5859
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
5960
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
60-
SqlScriptsTestExecutionListener.class);
61+
SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class);
6162
assertRegisteredListeners(DefaultListenersTestCase.class, expected);
6263
}
6364

@@ -69,7 +70,7 @@ public void defaultListenersMergedWithCustomListenerPrepended() {
6970
List<Class<?>> expected = asList(QuuxTestExecutionListener.class, ServletTestExecutionListener.class,
7071
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
7172
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
72-
SqlScriptsTestExecutionListener.class);
73+
SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class);
7374
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerPrependedTestCase.class, expected);
7475
}
7576

@@ -81,7 +82,8 @@ public void defaultListenersMergedWithCustomListenerAppended() {
8182
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
8283
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
8384
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
84-
SqlScriptsTestExecutionListener.class, BazTestExecutionListener.class);
85+
SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class,
86+
BazTestExecutionListener.class);
8587
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerAppendedTestCase.class, expected);
8688
}
8789

@@ -93,7 +95,8 @@ public void defaultListenersMergedWithCustomListenerInserted() {
9395
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
9496
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
9597
BarTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
96-
TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class);
98+
TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class,
99+
EventPublishingTestExecutionListener.class);
97100
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerInsertedTestCase.class, expected);
98101
}
99102

spring-test/src/test/java/org/springframework/test/context/cache/ClassLevelDirtiesContextTests.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,15 +22,18 @@
2222
import org.junit.BeforeClass;
2323
import org.junit.Test;
2424
import org.junit.runner.RunWith;
25-
import org.junit.runners.JUnit4;
2625

2726
import org.springframework.beans.factory.annotation.Autowired;
2827
import org.springframework.context.ApplicationContext;
2928
import org.springframework.context.annotation.Configuration;
3029
import org.springframework.test.annotation.DirtiesContext;
3130
import org.springframework.test.annotation.DirtiesContext.ClassMode;
3231
import org.springframework.test.context.ContextConfiguration;
32+
import org.springframework.test.context.TestExecutionListeners;
3333
import org.springframework.test.context.junit4.SpringRunner;
34+
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
35+
import org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener;
36+
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
3437

3538
import static org.junit.Assert.*;
3639
import static org.springframework.test.context.cache.ContextCacheTestUtils.*;
@@ -44,7 +47,6 @@
4447
* @author Sam Brannen
4548
* @since 3.0
4649
*/
47-
@RunWith(JUnit4.class)
4850
public class ClassLevelDirtiesContextTests {
4951

5052
private static final AtomicInteger cacheHits = new AtomicInteger(0);
@@ -146,6 +148,14 @@ public static void verifyFinalCacheState() {
146148

147149
@RunWith(SpringRunner.class)
148150
@ContextConfiguration
151+
// Ensure that we do not include the EventPublishingTestExecutionListener
152+
// since it will access the ApplicationContext for each method in the
153+
// TestExecutionListener API, thus distorting our cache hit/miss results.
154+
@TestExecutionListeners({
155+
DirtiesContextBeforeModesTestExecutionListener.class,
156+
DependencyInjectionTestExecutionListener.class,
157+
DirtiesContextTestExecutionListener.class
158+
})
149159
static abstract class BaseTestCase {
150160

151161
@Configuration

spring-test/src/test/java/org/springframework/test/context/configuration/interfaces/DirtiesContextInterfaceTests.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,12 +22,15 @@
2222
import org.junit.BeforeClass;
2323
import org.junit.Test;
2424
import org.junit.runner.RunWith;
25-
import org.junit.runners.JUnit4;
2625

2726
import org.springframework.beans.factory.annotation.Autowired;
2827
import org.springframework.context.ApplicationContext;
2928
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.test.context.TestExecutionListeners;
3030
import org.springframework.test.context.junit4.SpringRunner;
31+
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
32+
import org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener;
33+
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
3134

3235
import static org.junit.Assert.*;
3336
import static org.springframework.test.context.cache.ContextCacheTestUtils.*;
@@ -37,7 +40,6 @@
3740
* @author Sam Brannen
3841
* @since 4.3
3942
*/
40-
@RunWith(JUnit4.class)
4143
public class DirtiesContextInterfaceTests {
4244

4345
private static final AtomicInteger cacheHits = new AtomicInteger(0);
@@ -72,6 +74,14 @@ private void runTestClassAndAssertStats(Class<?> testClass, int expectedTestCoun
7274

7375

7476
@RunWith(SpringRunner.class)
77+
// Ensure that we do not include the EventPublishingTestExecutionListener
78+
// since it will access the ApplicationContext for each method in the
79+
// TestExecutionListener API, thus distorting our cache hit/miss results.
80+
@TestExecutionListeners({
81+
DirtiesContextBeforeModesTestExecutionListener.class,
82+
DependencyInjectionTestExecutionListener.class,
83+
DirtiesContextTestExecutionListener.class
84+
})
7585
public static class ClassLevelDirtiesContextWithCleanMethodsAndDefaultModeTestCase
7686
implements DirtiesContextTestInterface {
7787

spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerIntegrationTests.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.springframework.test.context.TestContext;
4242
import org.springframework.test.context.TestContextManager;
4343
import org.springframework.test.context.TestExecutionListener;
44-
import org.springframework.test.context.TestExecutionListeners;
4544
import org.springframework.test.context.event.annotation.AfterTestClass;
4645
import org.springframework.test.context.event.annotation.AfterTestExecution;
4746
import org.springframework.test.context.event.annotation.AfterTestMethod;
@@ -193,7 +192,6 @@ public void afterTestClassAnnotation() throws Exception {
193192

194193
@RunWith(SpringRunner.class)
195194
@ContextConfiguration(classes = TestEventListenerConfiguration.class)
196-
@TestExecutionListeners(EventPublishingTestExecutionListener.class)
197195
public static class ExampleTestCase {
198196

199197
@Traceable

0 commit comments

Comments
 (0)