diff --git a/spring-test/src/main/java/org/springframework/test/annotation/DirtiesContext.java b/spring-test/src/main/java/org/springframework/test/annotation/DirtiesContext.java
index a7f035097a1..4bdb423c5bc 100644
--- a/spring-test/src/main/java/org/springframework/test/annotation/DirtiesContext.java
+++ b/spring-test/src/main/java/org/springframework/test/annotation/DirtiesContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -26,36 +26,49 @@ import java.lang.annotation.Target;
/**
* Test annotation which indicates that the
* {@link org.springframework.context.ApplicationContext ApplicationContext}
- * associated with a test is dirty and should be closed:
+ * associated with a test is dirty and should therefore be closed
+ * and removed from the context cache.
*
- *
- * - after the current test, when declared at the method level
- * - after each test method in the current test class, when declared at the
- * class level with class mode set to {@link ClassMode#AFTER_EACH_TEST_METHOD
- * AFTER_EACH_TEST_METHOD}
- * - after the current test class, when declared at the class level with class
- * mode set to {@link ClassMode#AFTER_CLASS AFTER_CLASS}
- *
- *
- * Use this annotation if a test has modified the context — for example,
- * by replacing a bean definition or changing the state of a singleton bean.
- * Subsequent tests will be supplied a new context.
+ *
Use this annotation if a test has modified the context — for
+ * example, by modifying the state of a singleton bean, modifying the state
+ * of an embedded database, etc. Subsequent tests that request the same
+ * context will be supplied a new context.
*
*
{@code @DirtiesContext} may be used as a class-level and method-level
- * annotation within the same class. In such scenarios, the
- * {@code ApplicationContext} will be marked as dirty after any
- * such annotated method as well as after the entire class. If the
- * {@link ClassMode} is set to {@link ClassMode#AFTER_EACH_TEST_METHOD
- * AFTER_EACH_TEST_METHOD}, the context will be marked dirty after each test
- * method in the class.
+ * annotation within the same class or class hierarchy. In such scenarios, the
+ * {@code ApplicationContext} will be marked as dirty before or
+ * after any such annotated method as well as before or after the current test
+ * class, depending on the configured {@link #methodMode} and {@link #classMode}.
*
*
As of Spring Framework 4.0, this annotation may be used as a
* meta-annotation to create custom composed annotations.
*
+ *
Supported Test Phases
+ *
+ * - Before current test class: when declared at the class
+ * level with class mode set to {@link ClassMode#BEFORE_CLASS BEFORE_CLASS}
+ * - Before each test method in current test class: when
+ * declared at the class level with class mode set to
+ * {@link ClassMode#BEFORE_EACH_TEST_METHOD BEFORE_EACH_TEST_METHOD}
+ * - Before current test method: when declared at the
+ * method level with method mode set to
+ * {@link MethodMode#BEFORE_METHOD BEFORE_METHOD}
+ * - After current test method: when declared at the
+ * method level with method mode set to
+ * {@link MethodMode#AFTER_METHOD AFTER_METHOD}
+ * - After each test method in current test class: when
+ * declared at the class level with class mode set to
+ * {@link ClassMode#AFTER_EACH_TEST_METHOD AFTER_EACH_TEST_METHOD}
+ * - After current test class: when declared at the
+ * class level with class mode set to
+ * {@link ClassMode#AFTER_CLASS AFTER_CLASS}
+ *
+ *
* @author Sam Brannen
* @author Rod Johnson
* @since 2.0
* @see org.springframework.test.context.ContextConfiguration
+ * @see org.springframework.test.context.support.DirtiesContextTestExecutionListener
*/
@Documented
@Inherited
@@ -63,6 +76,27 @@ import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.METHOD })
public @interface DirtiesContext {
+ /**
+ * Defines modes which determine how {@code @DirtiesContext} is
+ * interpreted when used to annotate a test method.
+ *
+ * @since 4.2
+ */
+ static enum MethodMode {
+
+ /**
+ * The associated {@code ApplicationContext} will be marked as
+ * dirty before the corresponding test method.
+ */
+ BEFORE_METHOD,
+
+ /**
+ * The associated {@code ApplicationContext} will be marked as
+ * dirty after the corresponding test method.
+ */
+ AFTER_METHOD;
+ }
+
/**
* Defines modes which determine how {@code @DirtiesContext} is
* interpreted when used to annotate a test class.
@@ -73,15 +107,31 @@ public @interface DirtiesContext {
/**
* The associated {@code ApplicationContext} will be marked as
- * dirty after the test class.
+ * dirty before the test class.
+ *
+ * @since 4.2
*/
- AFTER_CLASS,
+ BEFORE_CLASS,
+
+ /**
+ * The associated {@code ApplicationContext} will be marked as
+ * dirty before each test method in the class.
+ *
+ * @since 4.2
+ */
+ BEFORE_EACH_TEST_METHOD,
/**
* The associated {@code ApplicationContext} will be marked as
* dirty after each test method in the class.
*/
- AFTER_EACH_TEST_METHOD;
+ AFTER_EACH_TEST_METHOD,
+
+ /**
+ * The associated {@code ApplicationContext} will be marked as
+ * dirty after the test class.
+ */
+ AFTER_CLASS;
}
/**
@@ -119,13 +169,23 @@ public @interface DirtiesContext {
}
+ /**
+ * The mode to use when a test method is annotated with
+ * {@code @DirtiesContext}.
+ * Defaults to {@link MethodMode#AFTER_METHOD AFTER_METHOD}.
+ *
Setting the method mode on an annotated test class has no meaning.
+ * For class-level control, use {@link #classMode} instead.
+ *
+ * @since 4.2
+ */
+ MethodMode methodMode() default MethodMode.AFTER_METHOD;
+
/**
* The mode to use when a test class is annotated with
* {@code @DirtiesContext}.
*
Defaults to {@link ClassMode#AFTER_CLASS AFTER_CLASS}.
- *
Note: Setting the class mode on an annotated test method has no meaning,
- * since the mere presence of the {@code @DirtiesContext} annotation on a
- * test method is sufficient.
+ *
Setting the class mode on an annotated test method has no meaning.
+ * For method-level control, use {@link #methodMode} instead.
*
* @since 3.0
*/
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/DirtiesContextTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/support/DirtiesContextTestExecutionListener.java
index 28473a24f47..7434a6d81c5 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/DirtiesContextTestExecutionListener.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/DirtiesContextTestExecutionListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -27,16 +27,18 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
+import org.springframework.test.annotation.DirtiesContext.MethodMode;
import org.springframework.test.context.TestContext;
import org.springframework.util.Assert;
import static org.springframework.test.annotation.DirtiesContext.ClassMode.*;
+import static org.springframework.test.annotation.DirtiesContext.MethodMode.*;
/**
* {@code TestExecutionListener} which provides support for marking the
* {@code ApplicationContext} associated with a test as dirty for
- * both test classes and test methods configured with the {@link DirtiesContext
- * @DirtiesContext} annotation.
+ * both test classes and test methods annotated with the
+ * {@link DirtiesContext @DirtiesContext} annotation.
*
* @author Sam Brannen
* @author Juergen Hoeller
@@ -57,79 +59,80 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
}
/**
- * If the current test method of the supplied {@linkplain TestContext test
- * context} is annotated with {@link DirtiesContext @DirtiesContext},
- * or if the test class is annotated with {@link DirtiesContext
- * @DirtiesContext} and the {@linkplain DirtiesContext#classMode() class
- * mode} is set to {@link ClassMode#AFTER_EACH_TEST_METHOD
- * AFTER_EACH_TEST_METHOD}, the {@linkplain ApplicationContext application
- * context} of the test context will be
- * {@linkplain TestContext#markApplicationContextDirty marked as dirty} and the
- * {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE}
- * in the test context will be set to {@code true}.
+ * If the test class of the supplied {@linkplain TestContext test context}
+ * is annotated with {@code @DirtiesContext} and the {@linkplain
+ * DirtiesContext#classMode() class mode} is set to {@link
+ * ClassMode#BEFORE_CLASS BEFORE_CLASS}, the {@linkplain ApplicationContext
+ * application context} of the test context will be
+ * {@linkplain TestContext#markApplicationContextDirty marked as dirty}, and the
+ * {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
+ * REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context will be set to
+ * {@code true}.
*/
@Override
- public void afterTestMethod(TestContext testContext) throws Exception {
- Class> testClass = testContext.getTestClass();
- Assert.notNull(testClass, "The test class of the supplied TestContext must not be null");
- Method testMethod = testContext.getTestMethod();
- Assert.notNull(testMethod, "The test method of the supplied TestContext must not be null");
-
- final String annotationType = DirtiesContext.class.getName();
- AnnotationAttributes methodAnnAttrs = AnnotatedElementUtils.getAnnotationAttributes(testMethod, annotationType);
- AnnotationAttributes classAnnAttrs = AnnotatedElementUtils.getAnnotationAttributes(testClass, annotationType);
- boolean methodDirtiesContext = methodAnnAttrs != null;
- boolean classDirtiesContext = classAnnAttrs != null;
- ClassMode classMode = classDirtiesContext ? classAnnAttrs. getEnum("classMode") : null;
-
- if (logger.isDebugEnabled()) {
- logger.debug(String.format(
- "After test method: context %s, class dirties context [%s], class mode [%s], method dirties context [%s].",
- testContext, classDirtiesContext, classMode, methodDirtiesContext));
- }
-
- if (methodDirtiesContext || (classMode == AFTER_EACH_TEST_METHOD)) {
- HierarchyMode hierarchyMode = methodDirtiesContext ? methodAnnAttrs. getEnum("hierarchyMode")
- : classAnnAttrs. getEnum("hierarchyMode");
- dirtyContext(testContext, hierarchyMode);
- }
+ public void beforeTestClass(TestContext testContext) throws Exception {
+ beforeOrAfterTestClass(testContext, "Before", BEFORE_CLASS);
}
/**
- * If the test class of the supplied {@linkplain TestContext test context} is
- * annotated with {@link DirtiesContext @DirtiesContext}, the
- * {@linkplain ApplicationContext application context} of the test context will
- * be {@linkplain TestContext#markApplicationContextDirty marked as dirty},
- * and the
+ * If the current test method of the supplied {@linkplain TestContext test
+ * context} is annotated with {@code @DirtiesContext} and the {@linkplain
+ * DirtiesContext#methodMode() method mode} is set to {@link
+ * MethodMode#BEFORE_METHOD BEFORE_METHOD}, or if the test class is
+ * annotated with {@code @DirtiesContext} and the {@linkplain
+ * DirtiesContext#classMode() class mode} is set to {@link
+ * ClassMode#BEFORE_EACH_TEST_METHOD BEFORE_EACH_TEST_METHOD}, the
+ * {@linkplain ApplicationContext application context} of the test context
+ * will be {@linkplain TestContext#markApplicationContextDirty marked as dirty} and the
+ * {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
+ * REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context will be set to {@code true}.
+ * @since 4.2
+ */
+ @Override
+ public void beforeTestMethod(TestContext testContext) throws Exception {
+ beforeOrAfterTestMethod(testContext, "Before", BEFORE_METHOD, BEFORE_EACH_TEST_METHOD);
+ }
+
+ /**
+ * If the current test method of the supplied {@linkplain TestContext test
+ * context} is annotated with {@code @DirtiesContext} and the {@linkplain
+ * DirtiesContext#methodMode() method mode} is set to {@link
+ * MethodMode#AFTER_METHOD AFTER_METHOD}, or if the test class is
+ * annotated with {@code @DirtiesContext} and the {@linkplain
+ * DirtiesContext#classMode() class mode} is set to {@link
+ * ClassMode#AFTER_EACH_TEST_METHOD AFTER_EACH_TEST_METHOD}, the
+ * {@linkplain ApplicationContext application context} of the test context
+ * will be {@linkplain TestContext#markApplicationContextDirty marked as dirty} and the
+ * {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
+ * REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context will be set to {@code true}.
+ */
+ @Override
+ public void afterTestMethod(TestContext testContext) throws Exception {
+ beforeOrAfterTestMethod(testContext, "After", AFTER_METHOD, AFTER_EACH_TEST_METHOD);
+ }
+
+ /**
+ * If the test class of the supplied {@linkplain TestContext test context}
+ * is annotated with {@code @DirtiesContext} and the {@linkplain
+ * DirtiesContext#classMode() class mode} is set to {@link
+ * ClassMode#AFTER_CLASS AFTER_CLASS}, the {@linkplain ApplicationContext
+ * application context} of the test context will be
+ * {@linkplain TestContext#markApplicationContextDirty marked as dirty}, and the
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
* REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context will be set to
* {@code true}.
*/
@Override
public void afterTestClass(TestContext testContext) throws Exception {
- Class> testClass = testContext.getTestClass();
- Assert.notNull(testClass, "The test class of the supplied TestContext must not be null");
-
- final String annotationType = DirtiesContext.class.getName();
- AnnotationAttributes annAttrs = AnnotatedElementUtils.getAnnotationAttributes(testClass, annotationType);
- boolean dirtiesContext = annAttrs != null;
-
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("After test class: context %s, dirtiesContext [%s].", testContext,
- dirtiesContext));
- }
- if (dirtiesContext) {
- HierarchyMode hierarchyMode = annAttrs. getEnum("hierarchyMode");
- dirtyContext(testContext, hierarchyMode);
- }
+ beforeOrAfterTestClass(testContext, "After", AFTER_CLASS);
}
/**
* Marks the {@linkplain ApplicationContext application context} of the supplied
* {@linkplain TestContext test context} as
* {@linkplain TestContext#markApplicationContextDirty(DirtiesContext.HierarchyMode) dirty}
- * and sets {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE}
- * in the test context to {@code true}.
+ * and sets {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
+ * REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context to {@code true}.
* @param testContext the test context whose application context should
* marked as dirty
* @param hierarchyMode the context cache clearing mode to be applied if the
@@ -141,4 +144,62 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
testContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE, Boolean.TRUE);
}
+ /**
+ * Perform the actual work for {@link #beforeTestMethod} and {@link #afterTestMethod}.
+ * @since 4.2
+ */
+ private void beforeOrAfterTestMethod(TestContext testContext, String phase, MethodMode requiredMethodMode,
+ ClassMode requiredClassMode) throws Exception {
+ Class> testClass = testContext.getTestClass();
+ Assert.notNull(testClass, "The test class of the supplied TestContext must not be null");
+ Method testMethod = testContext.getTestMethod();
+ Assert.notNull(testMethod, "The test method of the supplied TestContext must not be null");
+
+ final String annotationType = DirtiesContext.class.getName();
+ AnnotationAttributes methodAnnAttrs = AnnotatedElementUtils.getAnnotationAttributes(testMethod, annotationType);
+ AnnotationAttributes classAnnAttrs = AnnotatedElementUtils.getAnnotationAttributes(testClass, annotationType);
+ boolean methodAnnotated = methodAnnAttrs != null;
+ boolean classAnnotated = classAnnAttrs != null;
+ MethodMode methodMode = methodAnnotated ? methodAnnAttrs. getEnum("methodMode") : null;
+ ClassMode classMode = classAnnotated ? classAnnAttrs. getEnum("classMode") : null;
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(String.format(
+ "%s test method: context %s, class annotated with @DirtiesContext [%s] with mode [%s], method annotated with @DirtiesContext [%s] with mode [%s].",
+ phase, testContext, classAnnotated, classMode, methodAnnotated, methodMode));
+ }
+
+ if ((methodMode == requiredMethodMode) || (classMode == requiredClassMode)) {
+ HierarchyMode hierarchyMode = methodAnnotated ? methodAnnAttrs. getEnum("hierarchyMode")
+ : classAnnAttrs. getEnum("hierarchyMode");
+ dirtyContext(testContext, hierarchyMode);
+ }
+ }
+
+ /**
+ * Perform the actual work for {@link #beforeTestClass} and {@link #afterTestClass}.
+ * @since 4.2
+ */
+ private void beforeOrAfterTestClass(TestContext testContext, String phase, ClassMode requiredClassMode)
+ throws Exception {
+ Class> testClass = testContext.getTestClass();
+ Assert.notNull(testClass, "The test class of the supplied TestContext must not be null");
+
+ final String annotationType = DirtiesContext.class.getName();
+ AnnotationAttributes classAnnAttrs = AnnotatedElementUtils.getAnnotationAttributes(testClass, annotationType);
+ boolean classAnnotated = classAnnAttrs != null;
+ ClassMode classMode = classAnnotated ? classAnnAttrs. getEnum("classMode") : null;
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(String.format(
+ "%s test class: context %s, class annotated with @DirtiesContext [%s] with mode [%s].", phase,
+ testContext, classAnnotated, classMode));
+ }
+
+ if (classMode == requiredClassMode) {
+ HierarchyMode hierarchyMode = classAnnAttrs. getEnum("hierarchyMode");
+ dirtyContext(testContext, hierarchyMode);
+ }
+ }
+
}
diff --git a/spring-test/src/test/java/org/springframework/test/context/support/DirtiesContextTestExecutionListenerTests.java b/spring-test/src/test/java/org/springframework/test/context/support/DirtiesContextTestExecutionListenerTests.java
index 45c4d2657b9..23633a9de63 100644
--- a/spring-test/src/test/java/org/springframework/test/context/support/DirtiesContextTestExecutionListenerTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/support/DirtiesContextTestExecutionListenerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -20,6 +20,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.junit.Test;
+
import org.mockito.BDDMockito;
import org.springframework.test.annotation.DirtiesContext;
@@ -28,8 +29,10 @@ import org.springframework.test.annotation.DirtiesContext.HierarchyMode;
import org.springframework.test.context.TestContext;
import static org.mockito.BDDMockito.*;
+
import static org.springframework.test.annotation.DirtiesContext.ClassMode.*;
import static org.springframework.test.annotation.DirtiesContext.HierarchyMode.*;
+import static org.springframework.test.annotation.DirtiesContext.MethodMode.*;
/**
* Unit tests for {@link DirtiesContextTestExecutionListener}.
@@ -44,64 +47,113 @@ public class DirtiesContextTestExecutionListenerTests {
@Test
- public void afterTestMethodForDirtiesContextDeclaredLocallyOnMethod() throws Exception {
+ public void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnMethodWithBeforeMethodMode() throws Exception {
Class> clazz = getClass();
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
- given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("dirtiesContextDeclaredLocally"));
+ given(testContext.getTestMethod()).willReturn(
+ clazz.getDeclaredMethod("dirtiesContextDeclaredLocallyWithBeforeMethodMode"));
+ listener.beforeTestMethod(testContext);
+ verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
listener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
- public void afterTestMethodForDirtiesContextDeclaredOnMethodViaMetaAnnotation() throws Exception {
+ public void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnMethodWithAfterMethodMode() throws Exception {
Class> clazz = getClass();
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
- given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("dirtiesContextDeclaredViaMetaAnnotation"));
+ given(testContext.getTestMethod()).willReturn(
+ clazz.getDeclaredMethod("dirtiesContextDeclaredLocallyWithAfterMethodMode"));
+ listener.beforeTestMethod(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
listener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
- public void afterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
+ public void beforeAndAfterTestMethodForDirtiesContextDeclaredOnMethodViaMetaAnnotationWithAfterMethodMode()
+ throws Exception {
+ Class> clazz = getClass();
+ BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ given(testContext.getTestMethod()).willReturn(
+ clazz.getDeclaredMethod("dirtiesContextDeclaredViaMetaAnnotationWithAfterMethodMode"));
+ listener.beforeTestMethod(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
+ listener.afterTestMethod(testContext);
+ verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
+ }
+
+ @Test
+ public void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnClassBeforeEachTestMethod() throws Exception {
+ Class> clazz = DirtiesContextDeclaredLocallyBeforeEachTestMethod.class;
+ BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
+ listener.beforeTestMethod(testContext);
+ verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
+ listener.afterTestMethod(testContext);
+ verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
+ }
+
+ @Test
+ public void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
Class> clazz = DirtiesContextDeclaredLocallyAfterEachTestMethod.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
+ listener.beforeTestMethod(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
listener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
- public void afterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod() throws Exception {
+ public void beforeAndAfterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod()
+ throws Exception {
Class> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
+ listener.beforeTestMethod(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
listener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
- public void afterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
+ public void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnClassBeforeClass() throws Exception {
+ Class> clazz = DirtiesContextDeclaredLocallyBeforeClass.class;
+ BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
+ listener.beforeTestMethod(testContext);
+ listener.afterTestMethod(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
+ }
+
+ @Test
+ public void beforeAndAfterTestMethodForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
Class> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
+ listener.beforeTestMethod(testContext);
listener.afterTestMethod(testContext);
- verify(testContext, times(0)).markApplicationContextDirty(EXHAUSTIVE);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
- public void afterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
+ public void beforeAndAfterTestMethodForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
Class> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
+ listener.beforeTestMethod(testContext);
listener.afterTestMethod(testContext);
- verify(testContext, times(0)).markApplicationContextDirty(EXHAUSTIVE);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
- public void afterTestMethodForDirtiesContextViaMetaAnnotationWithOverrides() throws Exception {
+ public void beforeAndAfterTestMethodForDirtiesContextViaMetaAnnotationWithOverrides() throws Exception {
Class> clazz = DirtiesContextViaMetaAnnotationWithOverrides.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
given(testContext.getTestMethod()).willReturn(clazz.getDeclaredMethod("clean"));
+ listener.beforeTestMethod(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
listener.afterTestMethod(testContext);
verify(testContext, times(1)).markApplicationContextDirty(CURRENT_LEVEL);
}
@@ -109,77 +161,113 @@ public class DirtiesContextTestExecutionListenerTests {
// -------------------------------------------------------------------------
@Test
- public void afterTestClassForDirtiesContextDeclaredLocallyOnMethod() throws Exception {
+ public void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnMethod() throws Exception {
Class> clazz = getClass();
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ listener.beforeTestClass(testContext);
listener.afterTestClass(testContext);
- verify(testContext, times(0)).markApplicationContextDirty(EXHAUSTIVE);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
- public void afterTestClassForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
+ public void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnClassBeforeEachTestMethod() throws Exception {
+ Class> clazz = DirtiesContextDeclaredLocallyBeforeEachTestMethod.class;
+ BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ listener.beforeTestClass(testContext);
+ listener.afterTestClass(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
+ }
+
+ @Test
+ public void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnClassAfterEachTestMethod() throws Exception {
Class> clazz = DirtiesContextDeclaredLocallyAfterEachTestMethod.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ listener.beforeTestClass(testContext);
listener.afterTestClass(testContext);
- verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
- public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod() throws Exception {
+ public void beforeAndAfterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterEachTestMethod()
+ throws Exception {
Class> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterEachTestMethod.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ listener.beforeTestClass(testContext);
+ listener.afterTestClass(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
+ }
+
+ @Test
+ public void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnClassBeforeClass() throws Exception {
+ Class> clazz = DirtiesContextDeclaredLocallyBeforeClass.class;
+ BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ listener.beforeTestClass(testContext);
+ verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
listener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
- public void afterTestClassForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
+ public void beforeAndAfterTestClassForDirtiesContextDeclaredLocallyOnClassAfterClass() throws Exception {
Class> clazz = DirtiesContextDeclaredLocallyAfterClass.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ listener.beforeTestClass(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
listener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
- public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
+ public void beforeAndAfterTestClassForDirtiesContextDeclaredViaMetaAnnotationOnClassAfterClass() throws Exception {
Class> clazz = DirtiesContextDeclaredViaMetaAnnotationAfterClass.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ listener.beforeTestClass(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
listener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
@Test
- public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationWithOverrides() throws Exception {
+ public void beforeAndAfterTestClassForDirtiesContextDeclaredViaMetaAnnotationWithOverrides() throws Exception {
Class> clazz = DirtiesContextViaMetaAnnotationWithOverrides.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ listener.beforeTestClass(testContext);
listener.afterTestClass(testContext);
- verify(testContext, times(1)).markApplicationContextDirty(CURRENT_LEVEL);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
}
@Test
- public void afterTestClassForDirtiesContextDeclaredViaMetaAnnotationWithOverridenAttributes() throws Exception {
+ public void beforeAndAfterTestClassForDirtiesContextDeclaredViaMetaAnnotationWithOverridenAttributes()
+ throws Exception {
Class> clazz = DirtiesContextViaMetaAnnotationWithOverridenAttributes.class;
BDDMockito.> given(testContext.getTestClass()).willReturn(clazz);
+ listener.beforeTestClass(testContext);
+ verify(testContext, times(0)).markApplicationContextDirty(any(HierarchyMode.class));
listener.afterTestClass(testContext);
verify(testContext, times(1)).markApplicationContextDirty(EXHAUSTIVE);
}
// -------------------------------------------------------------------------
- @DirtiesContext
- void dirtiesContextDeclaredLocally() {
+ @DirtiesContext(methodMode = BEFORE_METHOD)
+ void dirtiesContextDeclaredLocallyWithBeforeMethodMode() {
/* no-op */
}
- @MetaDirty
- void dirtiesContextDeclaredViaMetaAnnotation() {
+ @DirtiesContext
+ void dirtiesContextDeclaredLocallyWithAfterMethodMode() {
+ /* no-op */
+ }
+
+ @MetaDirtyAfterMethod
+ void dirtiesContextDeclaredViaMetaAnnotationWithAfterMethodMode() {
/* no-op */
}
@DirtiesContext
@Retention(RetentionPolicy.RUNTIME)
- static @interface MetaDirty {
+ static @interface MetaDirtyAfterMethod {
}
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
@@ -192,6 +280,14 @@ public class DirtiesContextTestExecutionListenerTests {
static @interface MetaDirtyAfterClass {
}
+ @DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD)
+ static class DirtiesContextDeclaredLocallyBeforeEachTestMethod {
+
+ void clean() {
+ /* no-op */
+ }
+ }
+
@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)
static class DirtiesContextDeclaredLocallyAfterEachTestMethod {
@@ -217,6 +313,14 @@ public class DirtiesContextTestExecutionListenerTests {
}
}
+ @DirtiesContext(classMode = BEFORE_CLASS)
+ static class DirtiesContextDeclaredLocallyBeforeClass {
+
+ void clean() {
+ /* no-op */
+ }
+ }
+
@DirtiesContext(classMode = AFTER_CLASS)
static class DirtiesContextDeclaredLocallyAfterClass {
diff --git a/src/asciidoc/testing.adoc b/src/asciidoc/testing.adoc
index 6763d673da1..10e3bf09ca9 100644
--- a/src/asciidoc/testing.adoc
+++ b/src/asciidoc/testing.adoc
@@ -598,19 +598,17 @@ The following example demonstrates how to declare _inlined_ properties.
Indicates that the underlying Spring `ApplicationContext` has been __dirtied__ during
the execution of a test (i.e., modified or corrupted in some manner -- for example, by
-changing the state of a singleton bean) and should be closed, regardless of whether the
-test passed. When an application context is marked __dirty__, it is removed from the
-testing framework's cache and closed. As a consequence, the underlying Spring container
-will be rebuilt for any subsequent test that requires a context with the same
-configuration metadata.
+changing the state of a singleton bean) and should be closed. When an application
+context is marked __dirty__, it is removed from the testing framework's cache and
+closed. As a consequence, the underlying Spring container will be rebuilt for any
+subsequent test that requires a context with the same configuration metadata.
+
`@DirtiesContext` can be used as both a class-level and method-level annotation within
-the same test class. In such scenarios, the `ApplicationContext` is marked as __dirty__
-after any such annotated method as well as after the entire class. If the `ClassMode` is
-set to `AFTER_EACH_TEST_METHOD`, the context is marked dirty after each test method in
-the class.
+the same class or class hierarchy. In such scenarios, the `ApplicationContext` is marked
+as __dirty__ before or after any such annotated method as well as before or after the
+current test class, depending on the configured `methodMode` and `classMode`.
+
@@ -619,6 +617,22 @@ configuration scenarios:
+
+** Before the current test class, when declared on a class with class mode set to
+`BEFORE_CLASS`.
+
++
+
+[source,java,indent=0]
+[subs="verbatim,quotes"]
+----
+ **@DirtiesContext(classMode = BEFORE_CLASS)**
+ public class FreshContextTests {
+ // some tests that require a new Spring container
+ }
+----
+
++
+
** After the current test class, when declared on a class with class mode set to
`AFTER_CLASS` (i.e., the default class mode).
@@ -635,6 +649,22 @@ configuration scenarios:
+
+** Before each test method in the current test class, when declared on a class with class
+mode set to `BEFORE_EACH_TEST_METHOD.`
+
++
+
+[source,java,indent=0]
+[subs="verbatim,quotes"]
+----
+ **@DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD)**
+ public class FreshContextTests {
+ // some tests that require a new Spring container
+ }
+----
+
++
+
** After each test method in the current test class, when declared on a class with class
mode set to `AFTER_EACH_TEST_METHOD.`
@@ -643,7 +673,7 @@ mode set to `AFTER_EACH_TEST_METHOD.`
[source,java,indent=0]
[subs="verbatim,quotes"]
----
- **@DirtiesContext**(**classMode** = ClassMode.AFTER_EACH_TEST_METHOD)
+ **@DirtiesContext(classMode = AFTER_EACH_TEST_METHOD)**
public class ContextDirtyingTests {
// some tests that result in the Spring container being dirtied
}
@@ -651,7 +681,25 @@ mode set to `AFTER_EACH_TEST_METHOD.`
+
-** After the current test, when declared on a method.
+** Before the current test, when declared on a method with the method mode set to
+`BEFORE_METHOD`.
+
++
+
+[source,java,indent=0]
+[subs="verbatim,quotes"]
+----
+ **@DirtiesContext(methodMode = BEFORE_METHOD)**
+ @Test
+ public void testProcessWhichRequiresFreshAppCtx() {
+ // some logic that requires a new Spring container
+ }
+----
+
++
+
+** After the current test, when declared on a method with the method mode set to
+`AFTER_METHOD` (i.e., the default method mode).
+
@@ -693,7 +741,7 @@ specified instead, as seen below.
public class ExtendedTests extends BaseTests {
@Test
- @DirtiesContext(**hierarchyMode = HierarchyMode.CURRENT_LEVEL**)
+ @DirtiesContext(**hierarchyMode = CURRENT_LEVEL**)
public void test() {
// some logic that results in the child context being dirtied
}