[SPR-4702] Added support for @DirtiesContext at the test class level.
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1471 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
4ec91c47c3
commit
edab801f88
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.JUnitCore;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.junit4.TrackingRunListener;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
|
||||
|
||||
/**
|
||||
* JUnit 4 based integration test which verifies correct {@link ContextCache
|
||||
* application context caching} in conjunction with the
|
||||
* {@link SpringJUnit4ClassRunner} and the {@link DirtiesContext
|
||||
* @DirtiesContext} annotation at the class level.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class ClassLevelDirtiesContextTests {
|
||||
|
||||
/**
|
||||
* Asserts the statistics of the supplied context cache.
|
||||
*
|
||||
* @param usageScenario the scenario in which the statistics are used
|
||||
* @param expectedSize the expected number of contexts in the cache
|
||||
* @param expectedHitCount the expected hit count
|
||||
* @param expectedMissCount the expected miss count
|
||||
*/
|
||||
private static final void assertContextCacheStatistics(String usageScenario, int expectedSize,
|
||||
int expectedHitCount, int expectedMissCount) {
|
||||
|
||||
ContextCache contextCache = TestContextManager.contextCache;
|
||||
assertEquals("Verifying number of contexts in cache (" + usageScenario + ").", expectedSize,
|
||||
contextCache.size());
|
||||
assertEquals("Verifying number of cache hits (" + usageScenario + ").", expectedHitCount,
|
||||
contextCache.getHitCount());
|
||||
assertEquals("Verifying number of cache misses (" + usageScenario + ").", expectedMissCount,
|
||||
contextCache.getMissCount());
|
||||
}
|
||||
|
||||
private static final void runTestClassAndAssertRunListenerStats(Class<?> testClass) {
|
||||
final int expectedTestFailureCount = 0;
|
||||
final int expectedTestStartedCount = 1;
|
||||
final int expectedTestFinishedCount = 1;
|
||||
|
||||
TrackingRunListener listener = new TrackingRunListener();
|
||||
JUnitCore jUnitCore = new JUnitCore();
|
||||
jUnitCore.addListener(listener);
|
||||
jUnitCore.run(testClass);
|
||||
|
||||
assertEquals("Verifying number of failures for test class [" + testClass + "].", expectedTestFailureCount,
|
||||
listener.getTestFailureCount());
|
||||
assertEquals("Verifying number of tests started for test class [" + testClass + "].", expectedTestStartedCount,
|
||||
listener.getTestStartedCount());
|
||||
assertEquals("Verifying number of tests finished for test class [" + testClass + "].",
|
||||
expectedTestFinishedCount, listener.getTestFinishedCount());
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void verifyInitialCacheState() {
|
||||
ContextCache contextCache = TestContextManager.contextCache;
|
||||
contextCache.clear();
|
||||
contextCache.clearStatistics();
|
||||
assertContextCacheStatistics("BeforeClass", 0, 0, 0);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void verifyFinalCacheState() {
|
||||
assertContextCacheStatistics("AfterClass", 0, 3, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyDirtiesContextBehavior() throws Exception {
|
||||
|
||||
int hits = 0;
|
||||
int misses = 0;
|
||||
|
||||
runTestClassAndAssertRunListenerStats(CleanTestCase.class);
|
||||
assertContextCacheStatistics("after clean test class", 1, hits, ++misses);
|
||||
|
||||
runTestClassAndAssertRunListenerStats(ClassLevelDirtiesContextWithCleanMethodsTestCase.class);
|
||||
assertContextCacheStatistics("after class-level @DirtiesContext with clean test method", 0, ++hits, misses);
|
||||
|
||||
runTestClassAndAssertRunListenerStats(CleanTestCase.class);
|
||||
assertContextCacheStatistics("after clean test class", 1, hits, ++misses);
|
||||
|
||||
runTestClassAndAssertRunListenerStats(ClassLevelDirtiesContextWithDirtyMethodsTestCase.class);
|
||||
assertContextCacheStatistics("after class-level @DirtiesContext with dirty test method", 0, ++hits, misses);
|
||||
|
||||
runTestClassAndAssertRunListenerStats(ClassLevelDirtiesContextWithDirtyMethodsTestCase.class);
|
||||
assertContextCacheStatistics("after class-level @DirtiesContext with dirty test method", 0, hits, ++misses);
|
||||
|
||||
runTestClassAndAssertRunListenerStats(ClassLevelDirtiesContextWithDirtyMethodsTestCase.class);
|
||||
assertContextCacheStatistics("after class-level @DirtiesContext with dirty test method", 0, hits, ++misses);
|
||||
|
||||
runTestClassAndAssertRunListenerStats(CleanTestCase.class);
|
||||
assertContextCacheStatistics("after clean test class", 1, hits, ++misses);
|
||||
|
||||
runTestClassAndAssertRunListenerStats(ClassLevelDirtiesContextWithCleanMethodsTestCase.class);
|
||||
assertContextCacheStatistics("after class-level @DirtiesContext with clean test method", 0, ++hits, misses);
|
||||
}
|
||||
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class,
|
||||
DirtiesContextTestExecutionListener.class })
|
||||
@ContextConfiguration("/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml")
|
||||
public static abstract class BaseTestCase {
|
||||
|
||||
@Autowired
|
||||
protected ApplicationContext applicationContext;
|
||||
|
||||
|
||||
protected void assertApplicationContextWasAutowired() {
|
||||
assertNotNull("The application context should have been autowired.", this.applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class CleanTestCase extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void verifyContextWasAutowired() {
|
||||
assertApplicationContextWasAutowired();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@DirtiesContext
|
||||
public static final class ClassLevelDirtiesContextWithCleanMethodsTestCase extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void verifyContextWasAutowired() {
|
||||
assertApplicationContextWasAutowired();
|
||||
}
|
||||
}
|
||||
|
||||
@DirtiesContext
|
||||
public static final class ClassLevelDirtiesContextWithDirtyMethodsTestCase extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
@DirtiesContext
|
||||
public void dirtyContext() {
|
||||
assertApplicationContextWasAutowired();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
@ -25,47 +25,49 @@ import org.junit.AfterClass;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* JUnit 4 based unit test which verifies correct
|
||||
* {@link ContextCache application context caching} in conjunction with the
|
||||
* {@link SpringJUnit4ClassRunner} and the {@link DirtiesContext} annotation.
|
||||
*
|
||||
* JUnit 4 based unit test which verifies correct {@link ContextCache
|
||||
* application context caching} in conjunction with the
|
||||
* {@link SpringJUnit4ClassRunner} and the {@link DirtiesContext
|
||||
* @DirtiesContext} annotation at the method level.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = "/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml")
|
||||
public class SpringRunnerContextCacheTests implements ApplicationContextAware {
|
||||
@ContextConfiguration("/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml")
|
||||
public class SpringRunnerContextCacheTests {
|
||||
|
||||
private static ApplicationContext dirtiedApplicationContext;
|
||||
|
||||
@Autowired
|
||||
protected ApplicationContext applicationContext;
|
||||
|
||||
|
||||
/**
|
||||
* Asserts the statistics of the supplied context cache.
|
||||
*
|
||||
* @param usageScenario the scenario in which the statistics are used
|
||||
* @param expectedSize the expected number of contexts in the cache
|
||||
* @param expectedHitCount the expected hit count
|
||||
* @param expectedMissCount the expected miss count
|
||||
*/
|
||||
public static final void assertContextCacheStatistics(String usageScenario, int expectedSize,
|
||||
int expectedHitCount, int expectedMissCount) {
|
||||
public static final void assertContextCacheStatistics(String usageScenario, int expectedSize, int expectedHitCount,
|
||||
int expectedMissCount) {
|
||||
|
||||
ContextCache contextCache = TestContextManager.contextCache;
|
||||
assertEquals("Verifying number of contexts in cache (" + usageScenario + ").", expectedSize,
|
||||
contextCache.size());
|
||||
contextCache.size());
|
||||
assertEquals("Verifying number of cache hits (" + usageScenario + ").", expectedHitCount,
|
||||
contextCache.getHitCount());
|
||||
contextCache.getHitCount());
|
||||
assertEquals("Verifying number of cache misses (" + usageScenario + ").", expectedMissCount,
|
||||
contextCache.getMissCount());
|
||||
contextCache.getMissCount());
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
|
|
@ -82,37 +84,29 @@ public class SpringRunnerContextCacheTests implements ApplicationContextAware {
|
|||
assertContextCacheStatistics("AfterClass", 1, 1, 2);
|
||||
}
|
||||
|
||||
|
||||
public final void setApplicationContext(final ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DirtiesContext
|
||||
public void dirtyContext() {
|
||||
assertContextCacheStatistics("dirtyContext()", 1, 0, 1);
|
||||
assertNotNull("The application context should have been set due to ApplicationContextAware semantics.",
|
||||
this.applicationContext);
|
||||
assertNotNull("The application context should have been autowired.", this.applicationContext);
|
||||
SpringRunnerContextCacheTests.dirtiedApplicationContext = this.applicationContext;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyContextWasDirtied() {
|
||||
assertContextCacheStatistics("verifyContextWasDirtied()", 1, 0, 2);
|
||||
assertNotNull("The application context should have been set due to ApplicationContextAware semantics.",
|
||||
this.applicationContext);
|
||||
assertNotNull("The application context should have been autowired.", this.applicationContext);
|
||||
assertNotSame("The application context should have been 'dirtied'.",
|
||||
SpringRunnerContextCacheTests.dirtiedApplicationContext, this.applicationContext);
|
||||
SpringRunnerContextCacheTests.dirtiedApplicationContext, this.applicationContext);
|
||||
SpringRunnerContextCacheTests.dirtiedApplicationContext = this.applicationContext;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyContextWasNotDirtied() {
|
||||
assertContextCacheStatistics("verifyContextWasNotDirtied()", 1, 1, 2);
|
||||
assertNotNull("The application context should have been set due to ApplicationContextAware semantics.",
|
||||
this.applicationContext);
|
||||
assertNotNull("The application context should have been autowired.", this.applicationContext);
|
||||
assertSame("The application context should NOT have been 'dirtied'.",
|
||||
SpringRunnerContextCacheTests.dirtiedApplicationContext, this.applicationContext);
|
||||
SpringRunnerContextCacheTests.dirtiedApplicationContext, this.applicationContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -17,9 +17,9 @@
|
|||
package org.springframework.test.context.junit4;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.test.annotation.IfProfileValue;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.TestExecutionListener;
|
||||
|
|
@ -27,6 +27,7 @@ import org.springframework.test.context.TestExecutionListeners;
|
|||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@TestExecutionListeners(ClassLevelDisabledSpringRunnerTests.CustomTestExecutionListener.class)
|
||||
|
|
@ -41,6 +42,10 @@ public class ClassLevelDisabledSpringRunnerTests {
|
|||
|
||||
public static class CustomTestExecutionListener implements TestExecutionListener {
|
||||
|
||||
public void beforeTestClass(TestContext testContext) throws Exception {
|
||||
fail("A listener method for a disabled test should never be executed!");
|
||||
}
|
||||
|
||||
public void prepareTestInstance(TestContext testContext) throws Exception {
|
||||
fail("A listener method for a disabled test should never be executed!");
|
||||
}
|
||||
|
|
@ -52,6 +57,9 @@ public class ClassLevelDisabledSpringRunnerTests {
|
|||
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||
fail("A listener method for a disabled test should never be executed!");
|
||||
}
|
||||
}
|
||||
|
||||
public void afterTestClass(TestContext testContext) throws Exception {
|
||||
fail("A listener method for a disabled test should never be executed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.springframework.test.context.junit4;
|
|||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
import org.junit.runners.Suite.SuiteClasses;
|
||||
import org.springframework.test.context.ClassLevelDirtiesContextTests;
|
||||
import org.springframework.test.context.SpringRunnerContextCacheTests;
|
||||
|
||||
/**
|
||||
|
|
@ -59,6 +60,7 @@ StandardJUnit4FeaturesTests.class,//
|
|||
PropertiesBasedSpringJUnit4ClassRunnerAppCtxTests.class,//
|
||||
CustomDefaultContextLoaderClassSpringRunnerTests.class,//
|
||||
SpringRunnerContextCacheTests.class,//
|
||||
ClassLevelDirtiesContextTests.class,//
|
||||
ParameterizedDependencyInjectionTests.class,//
|
||||
ClassLevelTransactionalSpringRunnerTests.class,//
|
||||
MethodLevelTransactionalSpringRunnerTests.class,//
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ import org.testng.annotations.Test;
|
|||
* @author Sam Brannen
|
||||
* @since 2.5
|
||||
*/
|
||||
@org.junit.Ignore("TestNG tests should not be run by JUnit")
|
||||
@ContextConfiguration
|
||||
public class ConcreteTransactionalTestNGSpringContextTests extends AbstractTransactionalTestNGSpringContextTests
|
||||
implements BeanNameAware, InitializingBean {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import org.testng.annotations.Test;
|
|||
* TestNG based unit test to assess the claim in <a
|
||||
* href="http://opensource.atlassian.com/projects/spring/browse/SPR-3880"
|
||||
* target="_blank">SPR-3880</a> that a "context marked dirty using
|
||||
* {@link DirtiesContext @DirtiesContext} in [a] TestNG based test is not
|
||||
* {@link DirtiesContext @DirtiesContext} in [a] TestNG based test is not
|
||||
* reloaded in subsequent tests".
|
||||
* </p>
|
||||
* <p>
|
||||
|
|
@ -47,7 +47,6 @@ import org.testng.annotations.Test;
|
|||
* @author Sam Brannen
|
||||
* @since 2.5
|
||||
*/
|
||||
@org.junit.Ignore("TestNG tests should not be run by JUnit")
|
||||
@ContextConfiguration
|
||||
public class DirtiesContextTransactionalTestNGSpringContextTests extends AbstractTransactionalTestNGSpringContextTests {
|
||||
|
||||
|
|
@ -82,4 +81,5 @@ public class DirtiesContextTransactionalTestNGSpringContextTests extends Abstrac
|
|||
assertSame(this.applicationContext, this.dirtiedApplicationContext,
|
||||
"The application context should NOT have been 'dirtied'.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue