Document the effect of @DirtiesContext on test execution events
See gh-27757
This commit is contained in:
parent
8a510db00d
commit
d9c22e657f
|
@ -63,7 +63,10 @@ import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||||
* register a {@code TestExecutionListener} that loads the {@code ApplicationContext}
|
* register a {@code TestExecutionListener} that loads the {@code ApplicationContext}
|
||||||
* in the {@link org.springframework.test.context.TestExecutionListener#beforeTestClass
|
* in the {@link org.springframework.test.context.TestExecutionListener#beforeTestClass
|
||||||
* beforeTestClass} callback, and that {@code TestExecutionListener} must be registered
|
* beforeTestClass} callback, and that {@code TestExecutionListener} must be registered
|
||||||
* before the {@code EventPublishingTestExecutionListener}.
|
* before the {@code EventPublishingTestExecutionListener}. Similarly, if
|
||||||
|
* {@code @DirtiesContext} is used to remove the {@code ApplicationContext} from
|
||||||
|
* the context cache after the last test method in a given test class, the
|
||||||
|
* {@code AfterTestClassEvent} will not be published for that test class.
|
||||||
*
|
*
|
||||||
* <h3>Exception Handling</h3>
|
* <h3>Exception Handling</h3>
|
||||||
* <p>By default, if a test event listener throws an exception while consuming
|
* <p>By default, if a test event listener throws an exception while consuming
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2022 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.test.context.event;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.MethodOrderer.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.TestMethodOrder;
|
||||||
|
import org.junit.platform.testkit.engine.EngineTestKit;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext.MethodMode;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
import org.springframework.test.context.event.annotation.AfterTestClass;
|
||||||
|
import org.springframework.test.context.event.annotation.AfterTestExecution;
|
||||||
|
import org.springframework.test.context.event.annotation.AfterTestMethod;
|
||||||
|
import org.springframework.test.context.event.annotation.BeforeTestClass;
|
||||||
|
import org.springframework.test.context.event.annotation.BeforeTestExecution;
|
||||||
|
import org.springframework.test.context.event.annotation.BeforeTestMethod;
|
||||||
|
import org.springframework.test.context.event.annotation.PrepareTestInstance;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the {@link EventPublishingTestExecutionListener} which verify
|
||||||
|
* behavior for test context events when {@link DirtiesContext @DirtiesContext}
|
||||||
|
* is used.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 5.3.17
|
||||||
|
* @see https://github.com/spring-projects/spring-framework/issues/27757
|
||||||
|
*/
|
||||||
|
class DirtiesContextEventPublishingTests {
|
||||||
|
|
||||||
|
private static final List<Class<? extends TestContextEvent>> events = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
@AfterEach
|
||||||
|
void resetEvents() {
|
||||||
|
events.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void classLevelDirtiesContext() {
|
||||||
|
EngineTestKit.engine("junit-jupiter")//
|
||||||
|
.selectors(selectClass(ClassLevelDirtiesContextTestCase.class))//
|
||||||
|
.execute()//
|
||||||
|
.testEvents()//
|
||||||
|
.assertStatistics(stats -> stats.started(1).succeeded(1).failed(0));
|
||||||
|
|
||||||
|
assertThat(events).containsExactly(//
|
||||||
|
// BeforeTestClassEvent.class -- always missing for 1st test class by default
|
||||||
|
PrepareTestInstanceEvent.class, //
|
||||||
|
BeforeTestMethodEvent.class, //
|
||||||
|
BeforeTestExecutionEvent.class, //
|
||||||
|
AfterTestExecutionEvent.class, //
|
||||||
|
AfterTestMethodEvent.class, //
|
||||||
|
AfterTestClassEvent.class //
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void methodLevelAfterMethodDirtiesContext() {
|
||||||
|
EngineTestKit.engine("junit-jupiter")//
|
||||||
|
.selectors(selectClass(MethodLevelAfterMethodDirtiesContextTestCase.class))//
|
||||||
|
.execute()//
|
||||||
|
.testEvents()//
|
||||||
|
.assertStatistics(stats -> stats.started(1).succeeded(1).failed(0));
|
||||||
|
|
||||||
|
assertThat(events).containsExactly(//
|
||||||
|
// BeforeTestClassEvent.class -- always missing for 1st test class by default
|
||||||
|
PrepareTestInstanceEvent.class, //
|
||||||
|
BeforeTestMethodEvent.class, //
|
||||||
|
BeforeTestExecutionEvent.class, //
|
||||||
|
AfterTestExecutionEvent.class, //
|
||||||
|
AfterTestMethodEvent.class //
|
||||||
|
// AfterTestClassEvent.class -- missing b/c of @DirtiestContext "after method" at the method level
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void methodLevelAfterMethodDirtiesContextWithSubsequentTestMethod() {
|
||||||
|
EngineTestKit.engine("junit-jupiter")//
|
||||||
|
.selectors(selectClass(MethodLevelAfterMethodDirtiesContextWithSubsequentTestMethodTestCase.class))//
|
||||||
|
.execute()//
|
||||||
|
.testEvents()//
|
||||||
|
.assertStatistics(stats -> stats.started(2).succeeded(2).failed(0));
|
||||||
|
|
||||||
|
assertThat(events).containsExactly(//
|
||||||
|
// BeforeTestClassEvent.class -- always missing for 1st test class by default
|
||||||
|
// test1()
|
||||||
|
PrepareTestInstanceEvent.class, //
|
||||||
|
BeforeTestMethodEvent.class, //
|
||||||
|
BeforeTestExecutionEvent.class, //
|
||||||
|
AfterTestExecutionEvent.class, //
|
||||||
|
AfterTestMethodEvent.class, //
|
||||||
|
// test2()
|
||||||
|
PrepareTestInstanceEvent.class, //
|
||||||
|
BeforeTestMethodEvent.class, //
|
||||||
|
BeforeTestExecutionEvent.class, //
|
||||||
|
AfterTestExecutionEvent.class, //
|
||||||
|
AfterTestMethodEvent.class, //
|
||||||
|
AfterTestClassEvent.class // b/c @DirtiestContext is not applied for test2()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void methodLevelBeforeMethodDirtiesContext() {
|
||||||
|
EngineTestKit.engine("junit-jupiter")//
|
||||||
|
.selectors(selectClass(MethodLevelBeforeMethodDirtiesContextTestCase.class))//
|
||||||
|
.execute()//
|
||||||
|
.testEvents()//
|
||||||
|
.assertStatistics(stats -> stats.started(1).succeeded(1).failed(0));
|
||||||
|
|
||||||
|
assertThat(events).containsExactly(//
|
||||||
|
// BeforeTestClassEvent.class -- always missing for 1st test class by default
|
||||||
|
PrepareTestInstanceEvent.class, //
|
||||||
|
BeforeTestMethodEvent.class, //
|
||||||
|
BeforeTestExecutionEvent.class, //
|
||||||
|
AfterTestExecutionEvent.class, //
|
||||||
|
AfterTestMethodEvent.class, //
|
||||||
|
AfterTestClassEvent.class // b/c @DirtiestContext happens "before method" at the method level
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SpringJUnitConfig(Config.class)
|
||||||
|
// add unique property to get a unique ApplicationContext
|
||||||
|
@TestPropertySource(properties = "DirtiesContextEventPublishingTests.key = class-level")
|
||||||
|
@DirtiesContext
|
||||||
|
static class ClassLevelDirtiesContextTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SpringJUnitConfig(Config.class)
|
||||||
|
// add unique property to get a unique ApplicationContext
|
||||||
|
@TestPropertySource(properties = "DirtiesContextEventPublishingTests.key = method-level-after-method")
|
||||||
|
static class MethodLevelAfterMethodDirtiesContextTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DirtiesContext
|
||||||
|
void test1() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SpringJUnitConfig(Config.class)
|
||||||
|
// add unique property to get a unique ApplicationContext
|
||||||
|
@TestPropertySource(properties = "DirtiesContextEventPublishingTests.key = method-level-after-method-with-subsequent-test-method")
|
||||||
|
@TestMethodOrder(DisplayName.class)
|
||||||
|
static class MethodLevelAfterMethodDirtiesContextWithSubsequentTestMethodTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DirtiesContext
|
||||||
|
void test1() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test2() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SpringJUnitConfig(Config.class)
|
||||||
|
// add unique property to get a unique ApplicationContext
|
||||||
|
@TestPropertySource(properties = "DirtiesContextEventPublishingTests.key = method-level-before-method")
|
||||||
|
static class MethodLevelBeforeMethodDirtiesContextTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DirtiesContext(methodMode = MethodMode.BEFORE_METHOD)
|
||||||
|
void test() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class Config {
|
||||||
|
|
||||||
|
@BeforeTestClass
|
||||||
|
public void beforeTestClass(BeforeTestClassEvent e) {
|
||||||
|
events.add(e.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PrepareTestInstance
|
||||||
|
public void prepareTestInstance(PrepareTestInstanceEvent e) {
|
||||||
|
events.add(e.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeTestMethod
|
||||||
|
public void beforeTestMethod(BeforeTestMethodEvent e) {
|
||||||
|
events.add(e.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeTestExecution
|
||||||
|
public void beforeTestExecution(BeforeTestExecutionEvent e) {
|
||||||
|
events.add(e.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterTestExecution
|
||||||
|
public void afterTestExecution(AfterTestExecutionEvent e) {
|
||||||
|
events.add(e.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterTestMethod
|
||||||
|
public void afterTestMethod(AfterTestMethodEvent e) {
|
||||||
|
events.add(e.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterTestClass
|
||||||
|
public void afterTestClass(AfterTestClassEvent e) {
|
||||||
|
events.add(e.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2725,6 +2725,10 @@ If you wish to ensure that a `BeforeTestClassEvent` is always published for ever
|
||||||
class, you need to register a `TestExecutionListener` that loads the `ApplicationContext`
|
class, you need to register a `TestExecutionListener` that loads the `ApplicationContext`
|
||||||
in the `beforeTestClass` callback, and that `TestExecutionListener` must be registered
|
in the `beforeTestClass` callback, and that `TestExecutionListener` must be registered
|
||||||
_before_ the `EventPublishingTestExecutionListener`.
|
_before_ the `EventPublishingTestExecutionListener`.
|
||||||
|
|
||||||
|
Similarly, if `@DirtiesContext` is used to remove the `ApplicationContext` from the
|
||||||
|
context cache after the last test method in a given test class, the `AfterTestClassEvent`
|
||||||
|
will not be published for that test class.
|
||||||
====
|
====
|
||||||
|
|
||||||
In order to listen to test execution events, a Spring bean may choose to implement the
|
In order to listen to test execution events, a Spring bean may choose to implement the
|
||||||
|
|
Loading…
Reference in New Issue