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:
parent
c3d0459a4e
commit
353e092bf6
|
|
@ -44,8 +44,6 @@ package org.springframework.test.context;
|
||||||
* <p>Spring provides the following out-of-the-box implementations (all of
|
* <p>Spring provides the following out-of-the-box implementations (all of
|
||||||
* which implement {@code Ordered}):
|
* which implement {@code Ordered}):
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>{@link org.springframework.test.context.event.EventPublishingTestExecutionListener
|
|
||||||
* EventPublishingTestExecutionListener} (not registered by default)</li>
|
|
||||||
* <li>{@link org.springframework.test.context.web.ServletTestExecutionListener
|
* <li>{@link org.springframework.test.context.web.ServletTestExecutionListener
|
||||||
* ServletTestExecutionListener}</li>
|
* ServletTestExecutionListener}</li>
|
||||||
* <li>{@link org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener
|
* <li>{@link org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener
|
||||||
|
|
@ -58,6 +56,8 @@ package org.springframework.test.context;
|
||||||
* TransactionalTestExecutionListener}</li>
|
* TransactionalTestExecutionListener}</li>
|
||||||
* <li>{@link org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener
|
* <li>{@link org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener
|
||||||
* SqlScriptsTestExecutionListener}</li>
|
* SqlScriptsTestExecutionListener}</li>
|
||||||
|
* <li>{@link org.springframework.test.context.event.EventPublishingTestExecutionListener
|
||||||
|
* EventPublishingTestExecutionListener}</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
|
|
|
||||||
|
|
@ -16,15 +16,19 @@
|
||||||
|
|
||||||
package org.springframework.test.context.event;
|
package org.springframework.test.context.event;
|
||||||
|
|
||||||
import org.springframework.core.Ordered;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.springframework.test.context.TestContext;
|
import org.springframework.test.context.TestContext;
|
||||||
import org.springframework.test.context.TestExecutionListener;
|
import org.springframework.test.context.TestExecutionListener;
|
||||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link org.springframework.test.context.TestExecutionListener TestExecutionListener}
|
* {@link org.springframework.test.context.TestExecutionListener TestExecutionListener}
|
||||||
* that publishes test execution events to a Spring test
|
* that publishes test execution events to the
|
||||||
* {@link org.springframework.context.ApplicationContext ApplicationContext}.
|
* {@link org.springframework.context.ApplicationContext ApplicationContext}
|
||||||
|
* for the currently executing test. Events are only published if the
|
||||||
|
* {@code ApplicationContext} {@linkplain TestContext#hasApplicationContext()
|
||||||
|
* has already been loaded}.
|
||||||
*
|
*
|
||||||
* <h3>Supported Events</h3>
|
* <h3>Supported Events</h3>
|
||||||
* <ul>
|
* <ul>
|
||||||
|
|
@ -61,16 +65,8 @@ import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||||
* support. For further details, consult the class-level Javadoc for
|
* support. For further details, consult the class-level Javadoc for
|
||||||
* {@link org.springframework.context.event.EventListener @EventListener}.
|
* {@link org.springframework.context.event.EventListener @EventListener}.
|
||||||
*
|
*
|
||||||
* <h3>Listener Registration</h3>
|
|
||||||
* <p>Note that this {@code TestExecutionListener} is not registered by default,
|
|
||||||
* but it may be registered for a given test class via
|
|
||||||
* {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}
|
|
||||||
* or globally via the {@link org.springframework.core.io.support.SpringFactoriesLoader
|
|
||||||
* SpringFactoriesLoader} mechanism (consult the Javadoc and Spring reference manual for
|
|
||||||
* details).
|
|
||||||
*
|
|
||||||
* @author Frank Scheffler
|
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
|
* @author Frank Scheffler
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
* @see org.springframework.test.context.event.annotation.BeforeTestClass @BeforeTestClass
|
* @see org.springframework.test.context.event.annotation.BeforeTestClass @BeforeTestClass
|
||||||
* @see org.springframework.test.context.event.annotation.PrepareTestInstance @PrepareTestInstance
|
* @see org.springframework.test.context.event.annotation.PrepareTestInstance @PrepareTestInstance
|
||||||
|
|
@ -83,74 +79,80 @@ import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||||
public class EventPublishingTestExecutionListener extends AbstractTestExecutionListener {
|
public class EventPublishingTestExecutionListener extends AbstractTestExecutionListener {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns {@link Ordered#HIGHEST_PRECEDENCE}.
|
* Returns {@code 10000}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getOrder() {
|
public final int getOrder() {
|
||||||
return Ordered.HIGHEST_PRECEDENCE;
|
return 10_000;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishes a {@link BeforeTestClassEvent} to the {@code ApplicationContext}
|
* Publish a {@link BeforeTestClassEvent} to the {@code ApplicationContext}
|
||||||
* for the supplied {@link TestContext}.
|
* for the supplied {@link TestContext}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void beforeTestClass(TestContext testContext) {
|
public void beforeTestClass(TestContext testContext) {
|
||||||
testContext.getApplicationContext().publishEvent(new BeforeTestClassEvent(testContext));
|
publishEvent(testContext, BeforeTestClassEvent::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishes a {@link PrepareTestInstanceEvent} to the {@code ApplicationContext}
|
* Publish a {@link PrepareTestInstanceEvent} to the {@code ApplicationContext}
|
||||||
* for the supplied {@link TestContext}.
|
* for the supplied {@link TestContext}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void prepareTestInstance(TestContext testContext) {
|
public void prepareTestInstance(TestContext testContext) {
|
||||||
testContext.getApplicationContext().publishEvent(new PrepareTestInstanceEvent(testContext));
|
publishEvent(testContext, PrepareTestInstanceEvent::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishes a {@link BeforeTestMethodEvent} to the {@code ApplicationContext}
|
* Publish a {@link BeforeTestMethodEvent} to the {@code ApplicationContext}
|
||||||
* for the supplied {@link TestContext}.
|
* for the supplied {@link TestContext}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void beforeTestMethod(TestContext testContext) {
|
public void beforeTestMethod(TestContext testContext) {
|
||||||
testContext.getApplicationContext().publishEvent(new BeforeTestMethodEvent(testContext));
|
publishEvent(testContext, BeforeTestMethodEvent::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishes a {@link BeforeTestExecutionEvent} to the {@code ApplicationContext}
|
* Publish a {@link BeforeTestExecutionEvent} to the {@code ApplicationContext}
|
||||||
* for the supplied {@link TestContext}.
|
* for the supplied {@link TestContext}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void beforeTestExecution(TestContext testContext) {
|
public void beforeTestExecution(TestContext testContext) {
|
||||||
testContext.getApplicationContext().publishEvent(new BeforeTestExecutionEvent(testContext));
|
publishEvent(testContext, BeforeTestExecutionEvent::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishes an {@link AfterTestExecutionEvent} to the {@code ApplicationContext}
|
* Publish an {@link AfterTestExecutionEvent} to the {@code ApplicationContext}
|
||||||
* for the supplied {@link TestContext}.
|
* for the supplied {@link TestContext}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterTestExecution(TestContext testContext) {
|
public void afterTestExecution(TestContext testContext) {
|
||||||
testContext.getApplicationContext().publishEvent(new AfterTestExecutionEvent(testContext));
|
publishEvent(testContext, AfterTestExecutionEvent::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishes an {@link AfterTestMethodEvent} to the {@code ApplicationContext}
|
* Publish an {@link AfterTestMethodEvent} to the {@code ApplicationContext}
|
||||||
* for the supplied {@link TestContext}.
|
* for the supplied {@link TestContext}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterTestMethod(TestContext testContext) {
|
public void afterTestMethod(TestContext testContext) {
|
||||||
testContext.getApplicationContext().publishEvent(new AfterTestMethodEvent(testContext));
|
publishEvent(testContext, AfterTestMethodEvent::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Publishes an {@link AfterTestClassEvent} to the {@code ApplicationContext}
|
* Publish an {@link AfterTestClassEvent} to the {@code ApplicationContext}
|
||||||
* for the supplied {@link TestContext}.
|
* for the supplied {@link TestContext}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterTestClass(TestContext testContext) {
|
public void afterTestClass(TestContext testContext) {
|
||||||
testContext.getApplicationContext().publishEvent(new AfterTestClassEvent(testContext));
|
publishEvent(testContext, AfterTestClassEvent::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void publishEvent(TestContext testContext, Function<TestContext, TestContextEvent> eventFactory) {
|
||||||
|
if (testContext.hasApplicationContext()) {
|
||||||
|
testContext.getApplicationContext().publishEvent(eventFactory.apply(testContext));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ org.springframework.test.context.TestExecutionListener = \
|
||||||
org.springframework.test.context.support.DependencyInjectionTestExecutionListener,\
|
org.springframework.test.context.support.DependencyInjectionTestExecutionListener,\
|
||||||
org.springframework.test.context.support.DirtiesContextTestExecutionListener,\
|
org.springframework.test.context.support.DirtiesContextTestExecutionListener,\
|
||||||
org.springframework.test.context.transaction.TransactionalTestExecutionListener,\
|
org.springframework.test.context.transaction.TransactionalTestExecutionListener,\
|
||||||
org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener
|
org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener,\
|
||||||
|
org.springframework.test.context.event.EventPublishingTestExecutionListener
|
||||||
|
|
||||||
# Default ContextCustomizerFactory implementations for the Spring TestContext Framework
|
# Default ContextCustomizerFactory implementations for the Spring TestContext Framework
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.Ordered;
|
||||||
import org.springframework.core.annotation.AnnotationConfigurationException;
|
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.jdbc.SqlScriptsTestExecutionListener;
|
||||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||||
|
|
@ -57,7 +58,7 @@ public class TestExecutionListenersTests {
|
||||||
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
|
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
|
||||||
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
||||||
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
|
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
|
||||||
SqlScriptsTestExecutionListener.class);
|
SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class);
|
||||||
assertRegisteredListeners(DefaultListenersTestCase.class, expected);
|
assertRegisteredListeners(DefaultListenersTestCase.class, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +70,7 @@ public class TestExecutionListenersTests {
|
||||||
List<Class<?>> expected = asList(QuuxTestExecutionListener.class, ServletTestExecutionListener.class,
|
List<Class<?>> expected = asList(QuuxTestExecutionListener.class, ServletTestExecutionListener.class,
|
||||||
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
||||||
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
|
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
|
||||||
SqlScriptsTestExecutionListener.class);
|
SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class);
|
||||||
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerPrependedTestCase.class, expected);
|
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerPrependedTestCase.class, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,7 +82,8 @@ public class TestExecutionListenersTests {
|
||||||
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
|
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
|
||||||
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
||||||
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
|
DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class,
|
||||||
SqlScriptsTestExecutionListener.class, BazTestExecutionListener.class);
|
SqlScriptsTestExecutionListener.class, EventPublishingTestExecutionListener.class,
|
||||||
|
BazTestExecutionListener.class);
|
||||||
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerAppendedTestCase.class, expected);
|
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerAppendedTestCase.class, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +95,8 @@ public class TestExecutionListenersTests {
|
||||||
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
|
List<Class<?>> expected = asList(ServletTestExecutionListener.class,
|
||||||
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
|
||||||
BarTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
|
BarTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
|
||||||
TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class);
|
TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class,
|
||||||
|
EventPublishingTestExecutionListener.class);
|
||||||
assertRegisteredListeners(MergedDefaultListenersWithCustomListenerInsertedTestCase.class, expected);
|
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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
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;
|
||||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.TestExecutionListeners;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
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.junit.Assert.*;
|
||||||
import static org.springframework.test.context.cache.ContextCacheTestUtils.*;
|
import static org.springframework.test.context.cache.ContextCacheTestUtils.*;
|
||||||
|
|
@ -44,7 +47,6 @@ import static org.springframework.test.context.junit4.JUnitTestingUtils.*;
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
@RunWith(JUnit4.class)
|
|
||||||
public class ClassLevelDirtiesContextTests {
|
public class ClassLevelDirtiesContextTests {
|
||||||
|
|
||||||
private static final AtomicInteger cacheHits = new AtomicInteger(0);
|
private static final AtomicInteger cacheHits = new AtomicInteger(0);
|
||||||
|
|
@ -146,6 +148,14 @@ public class ClassLevelDirtiesContextTests {
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@ContextConfiguration
|
@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 {
|
static abstract class BaseTestCase {
|
||||||
|
|
||||||
@Configuration
|
@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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.context.TestExecutionListeners;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
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.junit.Assert.*;
|
||||||
import static org.springframework.test.context.cache.ContextCacheTestUtils.*;
|
import static org.springframework.test.context.cache.ContextCacheTestUtils.*;
|
||||||
|
|
@ -37,7 +40,6 @@ import static org.springframework.test.context.junit4.JUnitTestingUtils.*;
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
@RunWith(JUnit4.class)
|
|
||||||
public class DirtiesContextInterfaceTests {
|
public class DirtiesContextInterfaceTests {
|
||||||
|
|
||||||
private static final AtomicInteger cacheHits = new AtomicInteger(0);
|
private static final AtomicInteger cacheHits = new AtomicInteger(0);
|
||||||
|
|
@ -72,6 +74,14 @@ public class DirtiesContextInterfaceTests {
|
||||||
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
@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
|
public static class ClassLevelDirtiesContextWithCleanMethodsAndDefaultModeTestCase
|
||||||
implements DirtiesContextTestInterface {
|
implements DirtiesContextTestInterface {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.TestContext;
|
import org.springframework.test.context.TestContext;
|
||||||
import org.springframework.test.context.TestContextManager;
|
import org.springframework.test.context.TestContextManager;
|
||||||
import org.springframework.test.context.TestExecutionListener;
|
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.AfterTestClass;
|
||||||
import org.springframework.test.context.event.annotation.AfterTestExecution;
|
import org.springframework.test.context.event.annotation.AfterTestExecution;
|
||||||
import org.springframework.test.context.event.annotation.AfterTestMethod;
|
import org.springframework.test.context.event.annotation.AfterTestMethod;
|
||||||
|
|
@ -193,7 +192,6 @@ public class EventPublishingTestExecutionListenerIntegrationTests {
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@ContextConfiguration(classes = TestEventListenerConfiguration.class)
|
@ContextConfiguration(classes = TestEventListenerConfiguration.class)
|
||||||
@TestExecutionListeners(EventPublishingTestExecutionListener.class)
|
|
||||||
public static class ExampleTestCase {
|
public static class ExampleTestCase {
|
||||||
|
|
||||||
@Traceable
|
@Traceable
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,12 @@
|
||||||
|
|
||||||
package org.springframework.test.context.event;
|
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.Test;
|
||||||
|
import org.junit.rules.TestName;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.Answers;
|
import org.mockito.Answers;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
@ -26,16 +31,20 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import org.springframework.test.context.TestContext;
|
import org.springframework.test.context.TestContext;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
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.only;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link EventPublishingTestExecutionListener}.
|
* Unit tests for {@link EventPublishingTestExecutionListener}.
|
||||||
*
|
*
|
||||||
* @author Frank Scheffler
|
* @author Frank Scheffler
|
||||||
|
* @author Sam Brannen
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
|
@ -49,53 +58,97 @@ public class EventPublishingTestExecutionListenerTests {
|
||||||
@Captor
|
@Captor
|
||||||
private ArgumentCaptor<TestContextEvent> testExecutionEvent;
|
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
|
@Test
|
||||||
public void publishBeforeTestClassEvent() {
|
public void publishBeforeTestClassEvent() {
|
||||||
listener.beforeTestClass(testContext);
|
assertEvent(BeforeTestClassEvent.class, listener::beforeTestClass);
|
||||||
assertEvent(BeforeTestClassEvent.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publishPrepareTestInstanceEvent() {
|
public void publishPrepareTestInstanceEvent() {
|
||||||
listener.prepareTestInstance(testContext);
|
assertEvent(PrepareTestInstanceEvent.class, listener::prepareTestInstance);
|
||||||
assertEvent(PrepareTestInstanceEvent.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publishBeforeTestMethodEvent() {
|
public void publishBeforeTestMethodEvent() {
|
||||||
listener.beforeTestMethod(testContext);
|
assertEvent(BeforeTestMethodEvent.class, listener::beforeTestMethod);
|
||||||
assertEvent(BeforeTestMethodEvent.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publishBeforeTestExecutionEvent() {
|
public void publishBeforeTestExecutionEvent() {
|
||||||
listener.beforeTestExecution(testContext);
|
assertEvent(BeforeTestExecutionEvent.class, listener::beforeTestExecution);
|
||||||
assertEvent(BeforeTestExecutionEvent.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publishAfterTestExecutionEvent() {
|
public void publishAfterTestExecutionEvent() {
|
||||||
listener.afterTestExecution(testContext);
|
assertEvent(AfterTestExecutionEvent.class, listener::afterTestExecution);
|
||||||
assertEvent(AfterTestExecutionEvent.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publishAfterTestMethodEvent() {
|
public void publishAfterTestMethodEvent() {
|
||||||
listener.afterTestMethod(testContext);
|
assertEvent(AfterTestMethodEvent.class, listener::afterTestMethod);
|
||||||
assertEvent(AfterTestMethodEvent.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void publishAfterTestClassEvent() {
|
public void publishAfterTestClassEvent() {
|
||||||
listener.afterTestClass(testContext);
|
assertEvent(AfterTestClassEvent.class, listener::afterTestClass);
|
||||||
assertEvent(AfterTestClassEvent.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
verify(testContext.getApplicationContext(), only()).publishEvent(testExecutionEvent.capture());
|
||||||
assertThat(testExecutionEvent.getValue(), instanceOf(eventClass));
|
assertThat(testExecutionEvent.getValue(), instanceOf(eventClass));
|
||||||
assertThat(testExecutionEvent.getValue().getSource(), equalTo(testContext));
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1659,11 +1659,8 @@ subclasses instead.
|
||||||
==== `TestExecutionListener` Configuration
|
==== `TestExecutionListener` Configuration
|
||||||
|
|
||||||
Spring provides the following `TestExecutionListener` implementations that are registered
|
Spring provides the following `TestExecutionListener` implementations that are registered
|
||||||
exactly in the following order. Except for the `EventPublishingTestExecutionListener`,
|
by default, exactly in the following order:
|
||||||
each of these listeners is registered by default.
|
|
||||||
|
|
||||||
* `EventPublishingTestExecutionListener`: Publishes test execution events to the test's
|
|
||||||
`ApplicationContext` (see <<testcontext-test-execution-events>>).
|
|
||||||
* `ServletTestExecutionListener`: Configures Servlet API mocks for a
|
* `ServletTestExecutionListener`: Configures Servlet API mocks for a
|
||||||
`WebApplicationContext`.
|
`WebApplicationContext`.
|
||||||
* `DirtiesContextBeforeModesTestExecutionListener`: Handles the `@DirtiesContext`
|
* `DirtiesContextBeforeModesTestExecutionListener`: Handles the `@DirtiesContext`
|
||||||
|
|
@ -1676,6 +1673,8 @@ each of these listeners is registered by default.
|
||||||
default rollback semantics.
|
default rollback semantics.
|
||||||
* `SqlScriptsTestExecutionListener`: Runs SQL scripts configured by using the `@Sql`
|
* `SqlScriptsTestExecutionListener`: Runs SQL scripts configured by using the `@Sql`
|
||||||
annotation.
|
annotation.
|
||||||
|
* `EventPublishingTestExecutionListener`: Publishes test execution events to the test's
|
||||||
|
`ApplicationContext` (see <<testcontext-test-execution-events>>).
|
||||||
|
|
||||||
[[testcontext-tel-config-registering-tels]]
|
[[testcontext-tel-config-registering-tels]]
|
||||||
===== Registering `TestExecutionListener` Implementations
|
===== Registering `TestExecutionListener` Implementations
|
||||||
|
|
@ -1695,7 +1694,7 @@ become cumbersome if a custom listener needs to be used across a test suite. Sin
|
||||||
Framework 4.1, this issue is addressed through support for automatic discovery of default
|
Framework 4.1, this issue is addressed through support for automatic discovery of default
|
||||||
`TestExecutionListener` implementations through the `SpringFactoriesLoader` mechanism.
|
`TestExecutionListener` implementations through the `SpringFactoriesLoader` mechanism.
|
||||||
|
|
||||||
Specifically, the `spring-test` module declares all core default TestExecutionListener`
|
Specifically, the `spring-test` module declares all core default `TestExecutionListener`
|
||||||
implementations under the `org.springframework.test.context.TestExecutionListener` key in
|
implementations under the `org.springframework.test.context.TestExecutionListener` key in
|
||||||
its `META-INF/spring.factories` properties file. Third-party frameworks and developers
|
its `META-INF/spring.factories` properties file. Third-party frameworks and developers
|
||||||
can contribute their own `TestExecutionListener` implementations to the list of default
|
can contribute their own `TestExecutionListener` implementations to the list of default
|
||||||
|
|
@ -1786,11 +1785,10 @@ be replaced with the following:
|
||||||
==== Test Execution Events
|
==== Test Execution Events
|
||||||
|
|
||||||
The `EventPublishingTestExecutionListener` introduced in Spring Framework 5.2 offers an
|
The `EventPublishingTestExecutionListener` introduced in Spring Framework 5.2 offers an
|
||||||
alternative approach to implementing a custom `TestExecutionListener`. If the
|
alternative approach to implementing a custom `TestExecutionListener`. Components in the
|
||||||
`EventPublishingTestExecutionListener` is <<testcontext-tel-config-registering-tels,
|
test's `ApplicationContext` can listen to the following events published by the
|
||||||
registered>>, components in the `ApplicationContext` can listen to the following events
|
`EventPublishingTestExecutionListener`, each of which corresponds to a method in the
|
||||||
published by the `EventPublishingTestExecutionListener`. Each of these events corresponds
|
`TestExecutionListener` API.
|
||||||
to a method in the `TestExecutionListener` API.
|
|
||||||
|
|
||||||
* `BeforeTestClassEvent`
|
* `BeforeTestClassEvent`
|
||||||
* `PrepareTestInstanceEvent`
|
* `PrepareTestInstanceEvent`
|
||||||
|
|
@ -1800,6 +1798,8 @@ to a method in the `TestExecutionListener` API.
|
||||||
* `AfterTestMethodEvent`
|
* `AfterTestMethodEvent`
|
||||||
* `AfterTestClassEvent`
|
* `AfterTestClassEvent`
|
||||||
|
|
||||||
|
NOTE: These events are only published if the `ApplicationContext` has already been loaded.
|
||||||
|
|
||||||
These events may be consumed for various reasons, such as resetting mock beans or tracing
|
These events may be consumed for various reasons, such as resetting mock beans or tracing
|
||||||
test execution. One advantage of consuming test execution events rather than implementing
|
test execution. One advantage of consuming test execution events rather than implementing
|
||||||
a custom `TestExecutionListener` is that test execution events may be consumed by any
|
a custom `TestExecutionListener` is that test execution events may be consumed by any
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue