Introduce BEFORE METHOD/CLASS modes in @DirtiesContext

Prior to this commit, @DirtiesContext could only be used to close a
test ApplicationContext after an entire test class or after a test
method; however, there are some use cases for which it would be
beneficial to close a test ApplicationContext before a given test class
or test method -- for example, if some rogue (i.e., yet to be
determined) test within a large test suite has corrupted the original
configuration for the ApplicationContext.

This commit provides a solution to such testing challenges by
introducing the following modes for @DirtiesContext.

 - MethodMode.BEFORE_METHOD: configured via the new methodMode attribute

 - ClassMode.BEFORE_CLASS and ClassMode.BEFORE_EACH_TEST_METHOD: both
   configured via the existing classMode attribute

Issue: SPR-12429
This commit is contained in:
Sam Brannen
2015-03-22 18:42:41 +01:00
parent 6028a64444
commit e086a637d5
4 changed files with 397 additions and 124 deletions

View File

@@ -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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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.<Class<?>> 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 {