From edab801f888135f2ad822f32038f6b75006f7567 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 6 Jul 2009 12:58:56 +0000 Subject: [PATCH] [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 --- .../test/annotation/DirtiesContext.java | 24 ++- .../test/context/TestContextManager.java | 84 ++++++++- .../test/context/TestExecutionListener.java | 66 +++++-- .../junit4/SpringJUnit4ClassRunner.java | 76 +++++--- .../RunAfterTestClassCallbacks.java | 91 +++++++++ ....java => RunAfterTestMethodCallbacks.java} | 10 +- .../RunBeforeTestClassCallbacks.java | 64 +++++++ ...java => RunBeforeTestMethodCallbacks.java} | 12 +- .../AbstractTestExecutionListener.java | 20 +- .../DirtiesContextTestExecutionListener.java | 68 +++++-- .../AbstractTestNGSpringContextTests.java | 91 ++++++--- .../ClassLevelDirtiesContextTests.java | 174 ++++++++++++++++++ .../SpringRunnerContextCacheTests.java | 48 +++-- .../ClassLevelDisabledSpringRunnerTests.java | 14 +- .../junit4/SpringJUnit4SuiteTests.java | 2 + ...TransactionalTestNGSpringContextTests.java | 1 - ...TransactionalTestNGSpringContextTests.java | 4 +- 17 files changed, 714 insertions(+), 135 deletions(-) create mode 100644 org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestClassCallbacks.java rename org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/{RunSpringTestContextAfters.java => RunAfterTestMethodCallbacks.java} (90%) create mode 100644 org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunBeforeTestClassCallbacks.java rename org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/{RunSpringTestContextBefores.java => RunBeforeTestMethodCallbacks.java} (86%) create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/ClassLevelDirtiesContextTests.java diff --git a/org.springframework.test/src/main/java/org/springframework/test/annotation/DirtiesContext.java b/org.springframework.test/src/main/java/org/springframework/test/annotation/DirtiesContext.java index b22ff817820..5c8a66cb23c 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/annotation/DirtiesContext.java +++ b/org.springframework.test/src/main/java/org/springframework/test/annotation/DirtiesContext.java @@ -23,14 +23,30 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Test annotation to indicate that a test method dirties the context - * for the current test. - * + * Test annotation which indicates that the + * {@link org.springframework.context.ApplicationContext ApplicationContext} + * associated with a test is dirty and should be closed: + * + *

+ * 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. + *

+ *

+ * @DirtiesContext may be used as a class-level and + * method-level annotation within the same class. In such scenarios, the + * ApplicationContext will be marked as dirty after any + * such annotated method as well as after the entire class. + *

+ * * @author Rod Johnson * @author Sam Brannen * @since 2.0 */ -@Target({ElementType.METHOD}) +@Target( { ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DirtiesContext { diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/TestContextManager.java b/org.springframework.test/src/main/java/org/springframework/test/context/TestContextManager.java index d77ecf6b183..e3c111b6021 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/TestContextManager.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/TestContextManager.java @@ -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 before execution of any + * tests within the class. Should be called prior to any framework-specific + * before class methods (e.g., methods annotated with JUnit's + * {@link org.junit.BeforeClass @BeforeClass}). + *

+ * 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 not 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 before methods (e.g., methods annotated with - * JUnit's {@link org.junit.Before @Before} ). + * JUnit's {@link org.junit.Before @Before}). *

* The managed {@link TestContext} will be updated with the supplied * testInstance and testMethod. @@ -377,4 +410,51 @@ public class TestContextManager { } } + /** + * Hook for post-processing a test class after execution of all + * tests within the class. Should be called after any framework-specific + * after class methods (e.g., methods annotated with JUnit's + * {@link org.junit.AfterClass @AfterClass}). + *

+ * 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 listenersReversed = new ArrayList( + 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; + } + } + } diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/TestExecutionListener.java b/org.springframework.test/src/main/java/org/springframework/test/context/TestExecutionListener.java index 4f8524f07b2..4870c15d543 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/TestExecutionListener.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/TestExecutionListener.java @@ -31,25 +31,43 @@ package org.springframework.test.context; * Spring provides the following out-of-the-box implementations: *

* - * + * * @author Sam Brannen * @author Juergen Hoeller * @since 2.5 */ public interface TestExecutionListener { + /** + * Pre-processes a test class before execution of all tests within + * the class. + *

+ * This method should be called immediately before framework-specific + * before class lifecycle callbacks. + * + * @param testContext the test context for the test; never null + * @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. - *

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 null) + * {@link TestContext test context}, for example by injecting dependencies. + *

+ * 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 null * @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. - *

This method should be called immediately prior to any - * framework-specific before lifecycle callbacks. + *

+ * This method should be called immediately prior to framework-specific + * before lifecycle callbacks. + * * @param testContext the test context in which the test method will be - * executed (never null) + * executed; never null * @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. - *

This method should be called immediately after any - * framework-specific after lifecycle callbacks. + *

+ * This method should be called immediately after framework-specific + * after lifecycle callbacks. + * * @param testContext the test context in which the test method was - * executed (never null) + * executed; never null * @throws Exception allows any exception to propagate */ void afterTestMethod(TestContext testContext) throws Exception; + /** + * Post-processes a test class after execution of all tests within + * the class. + *

+ * This method should be called immediately after framework-specific + * after class lifecycle callbacks. + * + * @param testContext the test context for the test; never null + * @throws Exception allows any exception to propagate + */ + void afterTestClass(TestContext testContext) throws Exception; + } diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java index 732122edb1c..f9588c65f5b 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java @@ -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 @IfProfileValue 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()); } diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestClassCallbacks.java b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestClassCallbacks.java new file mode 100644 index 00000000000..0be5450c34b --- /dev/null +++ b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestClassCallbacks.java @@ -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; + +/** + * RunAfterTestClassCallbacks is a custom JUnit 4.5+ + * {@link Statement} which allows the Spring TestContext Framework 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 RunAfterTestClassCallbacks statement. + * + * @param next the next Statement in the execution chain + * @param testContextManager the TestContextManager upon which to call + * afterTestClass() + */ + 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 + * afterTestClass() throws an exception, it will also be + * tracked. Multiple exceptions will be combined into a + * {@link MultipleFailureException}. + */ + @Override + public void evaluate() throws Throwable { + List errors = new ArrayList(); + 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); + } +} diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunSpringTestContextAfters.java b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestMethodCallbacks.java similarity index 90% rename from org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunSpringTestContextAfters.java rename to org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestMethodCallbacks.java index 08bbec01740..a4e1c1e9183 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunSpringTestContextAfters.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestMethodCallbacks.java @@ -25,18 +25,18 @@ import org.junit.runners.model.Statement; import org.springframework.test.context.TestContextManager; /** - * RunSpringTestContextAfters is a custom JUnit 4.5+ + * RunAfterTestMethodCallbacks is a custom JUnit 4.5+ * {@link Statement} which allows the Spring TestContext Framework 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 RunSpringTestContextAfters statement. + * Constructs a new RunAfterTestMethodCallbacks statement. * * @param next the next Statement in the execution chain * @param testInstance the current test instance (never null) @@ -57,7 +57,7 @@ public class RunSpringTestContextAfters extends Statement { * @param testContextManager the TestContextManager upon which to call * afterTestMethod() */ - public RunSpringTestContextAfters(Statement next, Object testInstance, Method testMethod, + public RunAfterTestMethodCallbacks(Statement next, Object testInstance, Method testMethod, TestContextManager testContextManager) { this.next = next; this.testInstance = testInstance; diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunBeforeTestClassCallbacks.java b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunBeforeTestClassCallbacks.java new file mode 100644 index 00000000000..6e06239a122 --- /dev/null +++ b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunBeforeTestClassCallbacks.java @@ -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; + +/** + * RunBeforeTestClassCallbacks is a custom JUnit 4.5+ + * {@link Statement} which allows the Spring TestContext Framework 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 RunBeforeTestClassCallbacks statement. + * + * @param next the next Statement in the execution chain + * @param testContextManager the TestContextManager upon which to call + * beforeTestClass() + */ + 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(); + } + +} diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunSpringTestContextBefores.java b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunBeforeTestMethodCallbacks.java similarity index 86% rename from org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunSpringTestContextBefores.java rename to org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunBeforeTestMethodCallbacks.java index 1f9e76e8660..8833c390b16 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunSpringTestContextBefores.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/junit4/statements/RunBeforeTestMethodCallbacks.java @@ -22,18 +22,18 @@ import org.junit.runners.model.Statement; import org.springframework.test.context.TestContextManager; /** - * RunSpringTestContextBefores is a custom JUnit 4.5+ + * RunBeforeTestMethodCallbacks is a custom JUnit 4.5+ * {@link Statement} which allows the Spring TestContext Framework 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 RunSpringTestContextBefores statement. + * Constructs a new RunBeforeTestMethodCallbacks statement. * * @param next the next Statement in the execution chain * @param testInstance the current test instance (never null) @@ -54,7 +54,7 @@ public class RunSpringTestContextBefores extends Statement { * @param testContextManager the TestContextManager upon which to call * beforeTestMethod() */ - 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 { diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/support/AbstractTestExecutionListener.java b/org.springframework.test/src/main/java/org/springframework/test/context/support/AbstractTestExecutionListener.java index 4b2ac9223d4..e57d1a1dafc 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/support/AbstractTestExecutionListener.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/support/AbstractTestExecutionListener.java @@ -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 empty. Can be overridden by + * subclasses as necessary. + */ + public void beforeTestClass(TestContext testContext) throws Exception { + /* no-op */ + } + /** * The default implementation is empty. Can be overridden by * subclasses as necessary. @@ -54,4 +62,12 @@ public abstract class AbstractTestExecutionListener implements TestExecutionList /* no-op */ } + /** + * The default implementation is empty. Can be overridden by + * subclasses as necessary. + */ + public void afterTestClass(TestContext testContext) throws Exception { + /* no-op */ + } + } diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/support/DirtiesContextTestExecutionListener.java b/org.springframework.test/src/main/java/org/springframework/test/context/support/DirtiesContextTestExecutionListener.java index e3805e335db..98b00eca436 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/support/DirtiesContextTestExecutionListener.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/support/DirtiesContextTestExecutionListener.java @@ -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; /** - * TestExecutionListener which processes test methods configured - * with the {@link DirtiesContext @DirtiesContext} annotation. - * + * TestExecutionListener 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 true 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 true + * . + */ + 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 + * true. */ @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 + * true. + */ + @Override + public void afterTestClass(TestContext testContext) throws Exception { + Class testClass = testContext.getTestClass(); + Assert.notNull(testClass, "The test class of the supplied TestContext must not be null"); + + boolean dirtiesContext = testClass.isAnnotationPresent(DirtiesContext.class); + if (logger.isDebugEnabled()) { + logger.debug("After test class: context [" + testContext + "], dirtiesContext [" + dirtiesContext + "]."); + } + if (dirtiesContext) { + dirtyContext(testContext); } } diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.java b/org.springframework.test/src/main/java/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.java index 92bec927612..d2241912df6 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/testng/AbstractTestNGSpringContextTests.java @@ -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; /** *

@@ -47,19 +48,19 @@ import org.springframework.test.context.support.DirtiesContextTestExecutionListe * Concrete subclasses: *

* - * + * * @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 callback 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 callback 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(); + } + } diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/ClassLevelDirtiesContextTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/ClassLevelDirtiesContextTests.java new file mode 100644 index 00000000000..ecb53d3df30 --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/ClassLevelDirtiesContextTests.java @@ -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(); + } + } + +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/SpringRunnerContextCacheTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/SpringRunnerContextCacheTests.java index e2536d319b6..95aa0633b3f 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/SpringRunnerContextCacheTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/SpringRunnerContextCacheTests.java @@ -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); } } diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/ClassLevelDisabledSpringRunnerTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/ClassLevelDisabledSpringRunnerTests.java index 3f511783620..1c18259f1f9 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/ClassLevelDisabledSpringRunnerTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/ClassLevelDisabledSpringRunnerTests.java @@ -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!"); + } + } } diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java index d57f39ba27e..550ab3cd05e 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java @@ -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,// diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests.java index 30125a76a80..27adaef7efd 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/testng/ConcreteTransactionalTestNGSpringContextTests.java @@ -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 { diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests.java index be78b467598..f7faa13295b 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/testng/DirtiesContextTransactionalTestNGSpringContextTests.java @@ -32,7 +32,7 @@ import org.testng.annotations.Test; * TestNG based unit test to assess the claim in SPR-3880 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". *

*

@@ -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'."); } + }