[SPR-4702] Added support for @DirtiesContext at the test class level.
This commit is contained in:
@@ -23,14 +23,30 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Test annotation to indicate that a test method <em>dirties</em> the context
|
||||
* for the current test.
|
||||
*
|
||||
* Test annotation which indicates that the
|
||||
* {@link org.springframework.context.ApplicationContext ApplicationContext}
|
||||
* associated with a test is <em>dirty</em> and should be closed:
|
||||
* <ul>
|
||||
* <li>after the current test, when declared at the method level, or</li>
|
||||
* <li>after the current test class, when declared at the class level.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Use this annotation if a test has modified the context (for example, by
|
||||
* replacing a bean definition). Subsequent tests will be supplied a new
|
||||
* context.
|
||||
* </p>
|
||||
* <p>
|
||||
* <code>@DirtiesContext</code> may be used as a class-level and
|
||||
* method-level annotation within the same class. In such scenarios, the
|
||||
* <code>ApplicationContext</code> will be marked as <em>dirty</em> after any
|
||||
* such annotated method as well as after the entire class.
|
||||
* </p>
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Sam Brannen
|
||||
* @since 2.0
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Target( { ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface DirtiesContext {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 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.
|
||||
@@ -236,6 +236,39 @@ public class TestContextManager {
|
||||
return defaultListenerClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for pre-processing a test class <em>before</em> execution of any
|
||||
* tests within the class. Should be called prior to any framework-specific
|
||||
* <em>before class methods</em> (e.g., methods annotated with JUnit's
|
||||
* {@link org.junit.BeforeClass @BeforeClass}).
|
||||
* <p>
|
||||
* An attempt will be made to give each registered
|
||||
* {@link TestExecutionListener} a chance to pre-process the test class
|
||||
* execution. If a listener throws an exception, however, the remaining
|
||||
* registered listeners will <strong>not</strong> be called.
|
||||
*
|
||||
* @throws Exception if a registered TestExecutionListener throws an
|
||||
* exception
|
||||
* @see #getTestExecutionListeners()
|
||||
*/
|
||||
public void beforeTestClass() throws Exception {
|
||||
final Class<?> testClass = getTestContext().getTestClass();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("beforeTestClass(): class [" + testClass + "]");
|
||||
}
|
||||
|
||||
for (TestExecutionListener testExecutionListener : getTestExecutionListeners()) {
|
||||
try {
|
||||
testExecutionListener.beforeTestClass(getTestContext());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||
+ "] to process 'before class' callback for test class [" + testClass + "]", ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for preparing a test instance prior to execution of any individual
|
||||
* test methods, for example for injecting dependencies, etc. Should be
|
||||
@@ -279,7 +312,7 @@ public class TestContextManager {
|
||||
* {@link Method test method}, for example for setting up test fixtures,
|
||||
* starting a transaction, etc. Should be called prior to any
|
||||
* framework-specific <em>before methods</em> (e.g., methods annotated with
|
||||
* JUnit's {@link org.junit.Before @Before} ).
|
||||
* JUnit's {@link org.junit.Before @Before}).
|
||||
* <p>
|
||||
* The managed {@link TestContext} will be updated with the supplied
|
||||
* <code>testInstance</code> and <code>testMethod</code>.
|
||||
@@ -377,4 +410,51 @@ public class TestContextManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for post-processing a test class <em>after</em> execution of all
|
||||
* tests within the class. Should be called after any framework-specific
|
||||
* <em>after class methods</em> (e.g., methods annotated with JUnit's
|
||||
* {@link org.junit.AfterClass @AfterClass}).
|
||||
* <p>
|
||||
* Each registered {@link TestExecutionListener} will be given a chance to
|
||||
* post-process the test class. If a listener throws an exception, the
|
||||
* remaining registered listeners will still be called, but the first
|
||||
* exception thrown will be tracked and rethrown after all listeners have
|
||||
* executed. Note that registered listeners will be executed in the opposite
|
||||
* order in which they were registered.
|
||||
*
|
||||
* @throws Exception if a registered TestExecutionListener throws an
|
||||
* exception
|
||||
* @see #getTestExecutionListeners()
|
||||
*/
|
||||
public void afterTestClass() throws Exception {
|
||||
final Class<?> testClass = getTestContext().getTestClass();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("afterTestClass(): class [" + testClass + "]");
|
||||
}
|
||||
|
||||
// Traverse the TestExecutionListeners in reverse order to ensure proper
|
||||
// "wrapper"-style execution of listeners.
|
||||
List<TestExecutionListener> listenersReversed = new ArrayList<TestExecutionListener>(
|
||||
getTestExecutionListeners());
|
||||
Collections.reverse(listenersReversed);
|
||||
|
||||
Exception afterTestClassException = null;
|
||||
for (TestExecutionListener testExecutionListener : listenersReversed) {
|
||||
try {
|
||||
testExecutionListener.afterTestClass(getTestContext());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.warn("Caught exception while allowing TestExecutionListener [" + testExecutionListener
|
||||
+ "] to process 'after class' callback for test class [" + testClass + "]", ex);
|
||||
if (afterTestClassException == null) {
|
||||
afterTestClassException = ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (afterTestClassException != null) {
|
||||
throw afterTestClassException;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,25 +31,43 @@ package org.springframework.test.context;
|
||||
* Spring provides the following out-of-the-box implementations:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener DependencyInjectionTestExecutionListener}</li>
|
||||
* <li>{@link org.springframework.test.context.support.DirtiesContextTestExecutionListener DirtiesContextTestExecutionListener}</li>
|
||||
* <li>{@link org.springframework.test.context.transaction.TransactionalTestExecutionListener TransactionalTestExecutionListener}</li>
|
||||
* <li>
|
||||
* {@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener
|
||||
* DependencyInjectionTestExecutionListener}</li>
|
||||
* <li>
|
||||
* {@link org.springframework.test.context.support.DirtiesContextTestExecutionListener
|
||||
* DirtiesContextTestExecutionListener}</li>
|
||||
* <li>
|
||||
* {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener
|
||||
* TransactionalTestExecutionListener}</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public interface TestExecutionListener {
|
||||
|
||||
/**
|
||||
* Pre-processes a test class <em>before</em> execution of all tests within
|
||||
* the class.
|
||||
* <p>
|
||||
* This method should be called immediately before framework-specific
|
||||
* <em>before class</em> lifecycle callbacks.
|
||||
*
|
||||
* @param testContext the test context for the test; never <code>null</code>
|
||||
* @throws Exception allows any exception to propagate
|
||||
*/
|
||||
void beforeTestClass(TestContext testContext) throws Exception;
|
||||
|
||||
/**
|
||||
* Prepares the {@link Object test instance} of the supplied
|
||||
* {@link TestContext test context}, for example by injecting
|
||||
* dependencies.
|
||||
* <p>This method should be called immediately after instantiation
|
||||
* of the test instance but prior to any framework-specific lifecycle
|
||||
* callbacks.
|
||||
* @param testContext the test context for the test (never <code>null</code>)
|
||||
* {@link TestContext test context}, for example by injecting dependencies.
|
||||
* <p>
|
||||
* This method should be called immediately after instantiation of the test
|
||||
* instance but prior to any framework-specific lifecycle callbacks.
|
||||
*
|
||||
* @param testContext the test context for the test; never <code>null</code>
|
||||
* @throws Exception allows any exception to propagate
|
||||
*/
|
||||
void prepareTestInstance(TestContext testContext) throws Exception;
|
||||
@@ -59,10 +77,12 @@ public interface TestExecutionListener {
|
||||
* {@link java.lang.reflect.Method test method} in the supplied
|
||||
* {@link TestContext test context}, for example by setting up test
|
||||
* fixtures.
|
||||
* <p>This method should be called immediately prior to any
|
||||
* framework-specific <em>before</em> lifecycle callbacks.
|
||||
* <p>
|
||||
* This method should be called immediately prior to framework-specific
|
||||
* <em>before</em> lifecycle callbacks.
|
||||
*
|
||||
* @param testContext the test context in which the test method will be
|
||||
* executed (never <code>null</code>)
|
||||
* executed; never <code>null</code>
|
||||
* @throws Exception allows any exception to propagate
|
||||
*/
|
||||
void beforeTestMethod(TestContext testContext) throws Exception;
|
||||
@@ -72,12 +92,26 @@ public interface TestExecutionListener {
|
||||
* {@link java.lang.reflect.Method test method} in the supplied
|
||||
* {@link TestContext test context}, for example by tearing down test
|
||||
* fixtures.
|
||||
* <p>This method should be called immediately after any
|
||||
* framework-specific <em>after</em> lifecycle callbacks.
|
||||
* <p>
|
||||
* This method should be called immediately after framework-specific
|
||||
* <em>after</em> lifecycle callbacks.
|
||||
*
|
||||
* @param testContext the test context in which the test method was
|
||||
* executed (never <code>null</code>)
|
||||
* executed; never <code>null</code>
|
||||
* @throws Exception allows any exception to propagate
|
||||
*/
|
||||
void afterTestMethod(TestContext testContext) throws Exception;
|
||||
|
||||
/**
|
||||
* Post-processes a test class <em>after</em> execution of all tests within
|
||||
* the class.
|
||||
* <p>
|
||||
* This method should be called immediately after framework-specific
|
||||
* <em>after class</em> lifecycle callbacks.
|
||||
*
|
||||
* @param testContext the test context for the test; never <code>null</code>
|
||||
* @throws Exception allows any exception to propagate
|
||||
*/
|
||||
void afterTestClass(TestContext testContext) throws Exception;
|
||||
|
||||
}
|
||||
|
||||
@@ -39,8 +39,10 @@ import org.springframework.test.annotation.ProfileValueUtils;
|
||||
import org.springframework.test.annotation.Repeat;
|
||||
import org.springframework.test.annotation.Timed;
|
||||
import org.springframework.test.context.TestContextManager;
|
||||
import org.springframework.test.context.junit4.statements.RunSpringTestContextAfters;
|
||||
import org.springframework.test.context.junit4.statements.RunSpringTestContextBefores;
|
||||
import org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks;
|
||||
import org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks;
|
||||
import org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks;
|
||||
import org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks;
|
||||
import org.springframework.test.context.junit4.statements.SpringFailOnTimeout;
|
||||
import org.springframework.test.context.junit4.statements.SpringRepeat;
|
||||
|
||||
@@ -142,20 +144,6 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the parent implementation for creating the test instance and
|
||||
* then allows the {@link #getTestContextManager() TestContextManager} to
|
||||
* prepare the test instance before returning it.
|
||||
*
|
||||
* @see TestContextManager#prepareTestInstance(Object)
|
||||
*/
|
||||
@Override
|
||||
protected Object createTest() throws Exception {
|
||||
Object testInstance = super.createTest();
|
||||
getTestContextManager().prepareTestInstance(testInstance);
|
||||
return testInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a description suitable for an ignored test class if the test is
|
||||
* disabled via <code>@IfProfileValue</code> at the class-level, and
|
||||
@@ -191,6 +179,47 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
|
||||
super.run(notifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the {@link Statement} returned by the parent implementation with a
|
||||
* {@link RunBeforeTestClassCallbacks} statement, thus preserving the
|
||||
* default functionality but adding support for the Spring TestContext
|
||||
* Framework.
|
||||
*
|
||||
* @see RunBeforeTestClassCallbacks
|
||||
*/
|
||||
@Override
|
||||
protected Statement withBeforeClasses(Statement statement) {
|
||||
Statement junitBeforeClasses = super.withBeforeClasses(statement);
|
||||
return new RunBeforeTestClassCallbacks(junitBeforeClasses, getTestContextManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the {@link Statement} returned by the parent implementation with a
|
||||
* {@link RunAfterTestClassCallbacks} statement, thus preserving the default
|
||||
* functionality but adding support for the Spring TestContext Framework.
|
||||
*
|
||||
* @see RunAfterTestClassCallbacks
|
||||
*/
|
||||
@Override
|
||||
protected Statement withAfterClasses(Statement statement) {
|
||||
Statement junitAfterClasses = super.withAfterClasses(statement);
|
||||
return new RunAfterTestClassCallbacks(junitAfterClasses, getTestContextManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the parent implementation for creating the test instance and
|
||||
* then allows the {@link #getTestContextManager() TestContextManager} to
|
||||
* prepare the test instance before returning it.
|
||||
*
|
||||
* @see TestContextManager#prepareTestInstance(Object)
|
||||
*/
|
||||
@Override
|
||||
protected Object createTest() throws Exception {
|
||||
Object testInstance = super.createTest();
|
||||
getTestContextManager().prepareTestInstance(testInstance);
|
||||
return testInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the same logic as
|
||||
* {@link BlockJUnit4ClassRunner#runChild(FrameworkMethod, RunNotifier)},
|
||||
@@ -393,30 +422,31 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
|
||||
|
||||
/**
|
||||
* Wraps the {@link Statement} returned by the parent implementation with a
|
||||
* {@link RunSpringTestContextBefores} statement, thus preserving the
|
||||
* {@link RunBeforeTestMethodCallbacks} statement, thus preserving the
|
||||
* default functionality but adding support for the Spring TestContext
|
||||
* Framework.
|
||||
*
|
||||
* @see RunSpringTestContextBefores
|
||||
* @see RunBeforeTestMethodCallbacks
|
||||
*/
|
||||
@Override
|
||||
protected Statement withBefores(FrameworkMethod frameworkMethod, Object testInstance, Statement statement) {
|
||||
Statement junitBefores = super.withBefores(frameworkMethod, testInstance, statement);
|
||||
return new RunSpringTestContextBefores(junitBefores, testInstance, frameworkMethod.getMethod(),
|
||||
return new RunBeforeTestMethodCallbacks(junitBefores, testInstance, frameworkMethod.getMethod(),
|
||||
getTestContextManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the {@link Statement} returned by the parent implementation with a
|
||||
* {@link RunSpringTestContextAfters} statement, thus preserving the default
|
||||
* functionality but adding support for the Spring TestContext Framework.
|
||||
* {@link RunAfterTestMethodCallbacks} statement, thus preserving the
|
||||
* default functionality but adding support for the Spring TestContext
|
||||
* Framework.
|
||||
*
|
||||
* @see RunSpringTestContextAfters
|
||||
* @see RunAfterTestMethodCallbacks
|
||||
*/
|
||||
@Override
|
||||
protected Statement withAfters(FrameworkMethod frameworkMethod, Object testInstance, Statement statement) {
|
||||
Statement junitAfters = super.withAfters(frameworkMethod, testInstance, statement);
|
||||
return new RunSpringTestContextAfters(junitAfters, testInstance, frameworkMethod.getMethod(),
|
||||
return new RunAfterTestMethodCallbacks(junitAfters, testInstance, frameworkMethod.getMethod(),
|
||||
getTestContextManager());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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
|
||||
*
|
||||
* http://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.junit4.statements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.internal.runners.model.MultipleFailureException;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.springframework.test.context.TestContextManager;
|
||||
|
||||
/**
|
||||
* <code>RunAfterTestClassCallbacks</code> is a custom JUnit 4.5+
|
||||
* {@link Statement} which allows the <em>Spring TestContext Framework</em> to
|
||||
* be plugged into the JUnit execution chain by calling
|
||||
* {@link TestContextManager#afterTestClass() afterTestClass()} on the supplied
|
||||
* {@link TestContextManager}.
|
||||
*
|
||||
* @see #evaluate()
|
||||
* @see RunBeforeTestMethodCallbacks
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class RunAfterTestClassCallbacks extends Statement {
|
||||
|
||||
private final Statement next;
|
||||
|
||||
private final TestContextManager testContextManager;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new <code>RunAfterTestClassCallbacks</code> statement.
|
||||
*
|
||||
* @param next the next <code>Statement</code> in the execution chain
|
||||
* @param testContextManager the TestContextManager upon which to call
|
||||
* <code>afterTestClass()</code>
|
||||
*/
|
||||
public RunAfterTestClassCallbacks(Statement next, TestContextManager testContextManager) {
|
||||
this.next = next;
|
||||
this.testContextManager = testContextManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the next {@link Statement} in the execution chain (typically an
|
||||
* instance of {@link org.junit.internal.runners.statements.RunAfters
|
||||
* RunAfters}), catching any exceptions thrown, and then calls
|
||||
* {@link TestContextManager#afterTestClass()}. If the call to
|
||||
* <code>afterTestClass()</code> throws an exception, it will also be
|
||||
* tracked. Multiple exceptions will be combined into a
|
||||
* {@link MultipleFailureException}.
|
||||
*/
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
List<Throwable> errors = new ArrayList<Throwable>();
|
||||
try {
|
||||
this.next.evaluate();
|
||||
}
|
||||
catch (Throwable e) {
|
||||
errors.add(e);
|
||||
}
|
||||
|
||||
try {
|
||||
this.testContextManager.afterTestClass();
|
||||
}
|
||||
catch (Exception e) {
|
||||
errors.add(e);
|
||||
}
|
||||
|
||||
if (errors.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (errors.size() == 1) {
|
||||
throw errors.get(0);
|
||||
}
|
||||
throw new MultipleFailureException(errors);
|
||||
}
|
||||
}
|
||||
@@ -25,18 +25,18 @@ import org.junit.runners.model.Statement;
|
||||
import org.springframework.test.context.TestContextManager;
|
||||
|
||||
/**
|
||||
* <code>RunSpringTestContextAfters</code> is a custom JUnit 4.5+
|
||||
* <code>RunAfterTestMethodCallbacks</code> is a custom JUnit 4.5+
|
||||
* {@link Statement} which allows the <em>Spring TestContext Framework</em> to
|
||||
* be plugged into the JUnit execution chain by calling
|
||||
* {@link TestContextManager#afterTestMethod(Object, Method) afterTestMethod()}
|
||||
* on the supplied {@link TestContextManager}.
|
||||
*
|
||||
* @see #evaluate()
|
||||
* @see RunSpringTestContextBefores
|
||||
* @see RunBeforeTestMethodCallbacks
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class RunSpringTestContextAfters extends Statement {
|
||||
public class RunAfterTestMethodCallbacks extends Statement {
|
||||
|
||||
private final Statement next;
|
||||
|
||||
@@ -48,7 +48,7 @@ public class RunSpringTestContextAfters extends Statement {
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new <code>RunSpringTestContextAfters</code> statement.
|
||||
* Constructs a new <code>RunAfterTestMethodCallbacks</code> statement.
|
||||
*
|
||||
* @param next the next <code>Statement</code> in the execution chain
|
||||
* @param testInstance the current test instance (never <code>null</code>)
|
||||
@@ -57,7 +57,7 @@ public class RunSpringTestContextAfters extends Statement {
|
||||
* @param testContextManager the TestContextManager upon which to call
|
||||
* <code>afterTestMethod()</code>
|
||||
*/
|
||||
public RunSpringTestContextAfters(Statement next, Object testInstance, Method testMethod,
|
||||
public RunAfterTestMethodCallbacks(Statement next, Object testInstance, Method testMethod,
|
||||
TestContextManager testContextManager) {
|
||||
this.next = next;
|
||||
this.testInstance = testInstance;
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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
|
||||
*
|
||||
* http://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.junit4.statements;
|
||||
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.springframework.test.context.TestContextManager;
|
||||
|
||||
/**
|
||||
* <code>RunBeforeTestClassCallbacks</code> is a custom JUnit 4.5+
|
||||
* {@link Statement} which allows the <em>Spring TestContext Framework</em> to
|
||||
* be plugged into the JUnit execution chain by calling
|
||||
* {@link TestContextManager#beforeTestClass() beforeTestClass()} on the
|
||||
* supplied {@link TestContextManager}.
|
||||
*
|
||||
* @see #evaluate()
|
||||
* @see RunAfterTestMethodCallbacks
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class RunBeforeTestClassCallbacks extends Statement {
|
||||
|
||||
private final Statement next;
|
||||
|
||||
private final TestContextManager testContextManager;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new <code>RunBeforeTestClassCallbacks</code> statement.
|
||||
*
|
||||
* @param next the next <code>Statement</code> in the execution chain
|
||||
* @param testContextManager the TestContextManager upon which to call
|
||||
* <code>beforeTestClass()</code>
|
||||
*/
|
||||
public RunBeforeTestClassCallbacks(Statement next, TestContextManager testContextManager) {
|
||||
this.next = next;
|
||||
this.testContextManager = testContextManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link TestContextManager#beforeTestClass()} and then invokes the
|
||||
* next {@link Statement} in the execution chain (typically an instance of
|
||||
* {@link org.junit.internal.runners.statements.RunBefores RunBefores}).
|
||||
*/
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
this.testContextManager.beforeTestClass();
|
||||
this.next.evaluate();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,18 +22,18 @@ import org.junit.runners.model.Statement;
|
||||
import org.springframework.test.context.TestContextManager;
|
||||
|
||||
/**
|
||||
* <code>RunSpringTestContextBefores</code> is a custom JUnit 4.5+
|
||||
* <code>RunBeforeTestMethodCallbacks</code> is a custom JUnit 4.5+
|
||||
* {@link Statement} which allows the <em>Spring TestContext Framework</em> to
|
||||
* be plugged into the JUnit execution chain by calling
|
||||
* {@link TestContextManager#beforeTestMethod(Object, Method)
|
||||
* beforeTestMethod()} on the supplied {@link TestContextManager}.
|
||||
*
|
||||
* @see #evaluate()
|
||||
* @see RunSpringTestContextAfters
|
||||
* @see RunAfterTestMethodCallbacks
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class RunSpringTestContextBefores extends Statement {
|
||||
public class RunBeforeTestMethodCallbacks extends Statement {
|
||||
|
||||
private final Statement next;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class RunSpringTestContextBefores extends Statement {
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new <code>RunSpringTestContextBefores</code> statement.
|
||||
* Constructs a new <code>RunBeforeTestMethodCallbacks</code> statement.
|
||||
*
|
||||
* @param next the next <code>Statement</code> in the execution chain
|
||||
* @param testInstance the current test instance (never <code>null</code>)
|
||||
@@ -54,7 +54,7 @@ public class RunSpringTestContextBefores extends Statement {
|
||||
* @param testContextManager the TestContextManager upon which to call
|
||||
* <code>beforeTestMethod()</code>
|
||||
*/
|
||||
public RunSpringTestContextBefores(Statement next, Object testInstance, Method testMethod,
|
||||
public RunBeforeTestMethodCallbacks(Statement next, Object testInstance, Method testMethod,
|
||||
TestContextManager testContextManager) {
|
||||
this.next = next;
|
||||
this.testInstance = testInstance;
|
||||
@@ -66,7 +66,7 @@ public class RunSpringTestContextBefores extends Statement {
|
||||
* Calls {@link TestContextManager#beforeTestMethod(Object, Method)} and
|
||||
* then invokes the next {@link Statement} in the execution chain (typically
|
||||
* an instance of {@link org.junit.internal.runners.statements.RunBefores
|
||||
* RunBefores} ).
|
||||
* RunBefores}).
|
||||
*/
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 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.
|
||||
@@ -23,13 +23,21 @@ import org.springframework.test.context.TestExecutionListener;
|
||||
* Abstract implementation of the {@link TestExecutionListener} interface which
|
||||
* provides empty method stubs. Subclasses can extend this class and override
|
||||
* only those methods suitable for the task at hand.
|
||||
*
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public abstract class AbstractTestExecutionListener implements TestExecutionListener {
|
||||
|
||||
/**
|
||||
* The default implementation is <em>empty</em>. Can be overridden by
|
||||
* subclasses as necessary.
|
||||
*/
|
||||
public void beforeTestClass(TestContext testContext) throws Exception {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation is <em>empty</em>. Can be overridden by
|
||||
* subclasses as necessary.
|
||||
@@ -54,4 +62,12 @@ public abstract class AbstractTestExecutionListener implements TestExecutionList
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation is <em>empty</em>. Can be overridden by
|
||||
* subclasses as necessary.
|
||||
*/
|
||||
public void afterTestClass(TestContext testContext) throws Exception {
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 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,16 +20,16 @@ import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* <code>TestExecutionListener</code> which processes test methods configured
|
||||
* with the {@link DirtiesContext @DirtiesContext} annotation.
|
||||
*
|
||||
* <code>TestExecutionListener</code> which processes test classes and test
|
||||
* methods configured with the {@link DirtiesContext @DirtiesContext}
|
||||
* annotation.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
@@ -41,14 +41,27 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
|
||||
|
||||
|
||||
/**
|
||||
* If the current test method of the supplied
|
||||
* {@link TestContext test context} has been annotated with
|
||||
* {@link DirtiesContext @DirtiesContext}, the
|
||||
* {@link ApplicationContext application context} of the test context will
|
||||
* be {@link TestContext#markApplicationContextDirty() marked as dirty},
|
||||
* and the
|
||||
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE}
|
||||
* will be set to <code>true</code> in the test context.
|
||||
* Marks the {@link ApplicationContext application context} of the supplied
|
||||
* {@link TestContext test context} as
|
||||
* {@link TestContext#markApplicationContextDirty() dirty}, and sets the
|
||||
* {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE
|
||||
* REINJECT_DEPENDENCIES_ATTRIBUTE} in the test context to <code>true</code>
|
||||
* .
|
||||
*/
|
||||
protected void dirtyContext(TestContext testContext) {
|
||||
testContext.markApplicationContextDirty();
|
||||
testContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE, Boolean.TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current test method of the supplied {@link TestContext test
|
||||
* context} is annotated with {@link DirtiesContext @DirtiesContext},
|
||||
* the {@link ApplicationContext application context} of the test context
|
||||
* will be {@link 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</code>.
|
||||
*/
|
||||
@Override
|
||||
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||
@@ -59,11 +72,32 @@ public class DirtiesContextTestExecutionListener extends AbstractTestExecutionLi
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("After test method: context [" + testContext + "], dirtiesContext [" + dirtiesContext + "].");
|
||||
}
|
||||
|
||||
if (dirtiesContext) {
|
||||
testContext.markApplicationContextDirty();
|
||||
testContext.setAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE,
|
||||
Boolean.TRUE);
|
||||
dirtyContext(testContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the test class of the supplied {@link TestContext test context} is
|
||||
* annotated with {@link DirtiesContext @DirtiesContext}, the
|
||||
* {@link ApplicationContext application context} of the test context will
|
||||
* be {@link 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</code>.
|
||||
*/
|
||||
@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");
|
||||
|
||||
boolean dirtiesContext = testClass.isAnnotationPresent(DirtiesContext.class);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("After test class: context [" + testContext + "], dirtiesContext [" + dirtiesContext + "].");
|
||||
}
|
||||
if (dirtiesContext) {
|
||||
dirtyContext(testContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2009 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.
|
||||
@@ -16,17 +16,11 @@
|
||||
|
||||
package org.springframework.test.context.testng;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.testng.IHookCallBack;
|
||||
import org.testng.IHookable;
|
||||
import org.testng.ITestResult;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
@@ -35,6 +29,13 @@ import org.springframework.test.context.TestContextManager;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
|
||||
import org.testng.IHookCallBack;
|
||||
import org.testng.IHookable;
|
||||
import org.testng.ITestResult;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -47,19 +48,19 @@ import org.springframework.test.context.support.DirtiesContextTestExecutionListe
|
||||
* Concrete subclasses:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Typically declare a class-level
|
||||
* {@link ContextConfiguration @ContextConfiguration} annotation to configure
|
||||
* the {@link ApplicationContext application context}
|
||||
* <li>Typically declare a class-level {@link ContextConfiguration
|
||||
* @ContextConfiguration} annotation to configure the
|
||||
* {@link ApplicationContext application context}
|
||||
* {@link ContextConfiguration#locations() resource locations}.
|
||||
* <em>If your test does not need to load an application context, you may choose
|
||||
* to omit the {@link ContextConfiguration @ContextConfiguration} declaration
|
||||
* to omit the {@link ContextConfiguration @ContextConfiguration} declaration
|
||||
* and to configure the appropriate
|
||||
* {@link org.springframework.test.context.TestExecutionListener TestExecutionListeners}
|
||||
* manually.</em></li>
|
||||
* <li>Must have constructors which either implicitly or explicitly delegate to
|
||||
* <code>super();</code>.</li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
@@ -70,7 +71,7 @@ import org.springframework.test.context.support.DirtiesContextTestExecutionListe
|
||||
* @see org.springframework.test.context.junit38.AbstractJUnit38SpringContextTests
|
||||
* @see org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests
|
||||
*/
|
||||
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class})
|
||||
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class })
|
||||
public abstract class AbstractTestNGSpringContextTests implements IHookable, ApplicationContextAware {
|
||||
|
||||
/** Logger available to subclasses */
|
||||
@@ -88,8 +89,8 @@ public abstract class AbstractTestNGSpringContextTests implements IHookable, App
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new AbstractTestNGSpringContextTests instance and
|
||||
* initializes the internal {@link TestContextManager} for the current test.
|
||||
* Construct a new AbstractTestNGSpringContextTests instance and initialize
|
||||
* the internal {@link TestContextManager} for the current test.
|
||||
*/
|
||||
public AbstractTestNGSpringContextTests() {
|
||||
this.testContextManager = new TestContextManager(getClass());
|
||||
@@ -98,21 +99,36 @@ public abstract class AbstractTestNGSpringContextTests implements IHookable, App
|
||||
/**
|
||||
* Set the {@link ApplicationContext} to be used by this test instance,
|
||||
* provided via {@link ApplicationContextAware} semantics.
|
||||
*
|
||||
* @param applicationContext the applicationContext to set
|
||||
*/
|
||||
public final void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the configured {@link TestContextManager} to call
|
||||
* {@link TestContextManager#beforeTestClass() 'before test class'}
|
||||
* callbacks.
|
||||
*
|
||||
* @throws Exception if a registered TestExecutionListener throws an
|
||||
* exception
|
||||
*/
|
||||
@BeforeClass(alwaysRun = true)
|
||||
protected void springTestContextBeforeTestClass() throws Exception {
|
||||
this.testContextManager.beforeTestClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the configured {@link TestContextManager} to
|
||||
* {@link TestContextManager#prepareTestInstance(Object) prepare} this test
|
||||
* instance prior to execution of any individual tests, for example for
|
||||
* injecting dependencies, etc.
|
||||
* @throws Exception if a registered TestExecutionListener throws an exception
|
||||
*
|
||||
* @throws Exception if a registered TestExecutionListener throws an
|
||||
* exception
|
||||
*/
|
||||
@BeforeClass(alwaysRun = true)
|
||||
@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextBeforeTestClass")
|
||||
protected void springTestContextPrepareTestInstance() throws Exception {
|
||||
this.testContextManager.prepareTestInstance(this);
|
||||
}
|
||||
@@ -121,6 +137,7 @@ public abstract class AbstractTestNGSpringContextTests implements IHookable, App
|
||||
* Delegates to the configured {@link TestContextManager} to
|
||||
* {@link TestContextManager#beforeTestMethod(Object,Method) pre-process}
|
||||
* the test method before the actual test is executed.
|
||||
*
|
||||
* @param testMethod the test method which is about to be executed.
|
||||
* @throws Exception allows all exceptions to propagate.
|
||||
*/
|
||||
@@ -130,22 +147,30 @@ public abstract class AbstractTestNGSpringContextTests implements IHookable, App
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the
|
||||
* {@link IHookCallBack#runTestMethod(ITestResult) test method} in the
|
||||
* supplied <code>callback</code> to execute the actual test and then
|
||||
* tracks the exception thrown during test execution, if any.
|
||||
* @see org.testng.IHookable#run(org.testng.IHookCallBack, org.testng.ITestResult)
|
||||
* Delegates to the {@link IHookCallBack#runTestMethod(ITestResult) test
|
||||
* method} in the supplied <code>callback</code> to execute the actual test
|
||||
* and then tracks the exception thrown during test execution, if any.
|
||||
*
|
||||
* @see org.testng.IHookable#run(org.testng.IHookCallBack,
|
||||
* org.testng.ITestResult)
|
||||
*/
|
||||
public void run(IHookCallBack callBack, ITestResult testResult) {
|
||||
callBack.runTestMethod(testResult);
|
||||
this.testException = testResult.getThrowable();
|
||||
|
||||
Throwable testResultException = testResult.getThrowable();
|
||||
if (testResultException instanceof InvocationTargetException) {
|
||||
testResultException = ((InvocationTargetException) testResultException).getCause();
|
||||
}
|
||||
this.testException = testResultException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the configured {@link TestContextManager} to
|
||||
* {@link TestContextManager#afterTestMethod(Object, Method, Throwable) post-process}
|
||||
* the test method after the actual test has executed.
|
||||
* @param testMethod the test method which has just been executed on the test instance
|
||||
* {@link TestContextManager#afterTestMethod(Object, Method, Throwable)
|
||||
* post-process} the test method after the actual test has executed.
|
||||
*
|
||||
* @param testMethod the test method which has just been executed on the
|
||||
* test instance
|
||||
* @throws Exception allows all exceptions to propagate
|
||||
*/
|
||||
@AfterMethod(alwaysRun = true)
|
||||
@@ -158,4 +183,16 @@ public abstract class AbstractTestNGSpringContextTests implements IHookable, App
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the configured {@link TestContextManager} to call
|
||||
* {@link TestContextManager#afterTestClass() 'after test class'} callbacks.
|
||||
*
|
||||
* @throws Exception if a registered TestExecutionListener throws an
|
||||
* exception
|
||||
*/
|
||||
@AfterClass(alwaysRun = true)
|
||||
protected void springTestContextAfterTestClass() throws Exception {
|
||||
this.testContextManager.afterTestClass();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user