diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractJUnit4SpringContextTests.java b/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractJUnit4SpringContextTests.java
index 6524b65db4..72b300be0c 100644
--- a/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractJUnit4SpringContextTests.java
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractJUnit4SpringContextTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package org.springframework.test.context.junit4;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
@@ -36,12 +37,12 @@ import org.springframework.test.context.web.ServletTestExecutionListener;
* in a JUnit environment.
*
*
Concrete subclasses should typically declare a class-level
- * {@link ContextConfiguration @ContextConfiguration} annotation to
- * configure the {@link ApplicationContext application context} {@link
+ * {@link ContextConfiguration @ContextConfiguration} annotation to
+ * configure the {@linkplain ApplicationContext application context} {@link
* ContextConfiguration#locations() resource locations} or {@link
* ContextConfiguration#classes() annotated classes}. If your test does not
- * need to load an application context, you may choose to omit the {@link
- * ContextConfiguration @ContextConfiguration} declaration and to configure
+ * need to load an application context, you may choose to omit the
+ * {@link ContextConfiguration @ContextConfiguration} declaration and to configure
* the appropriate {@link org.springframework.test.context.TestExecutionListener
* TestExecutionListeners} manually.
*
@@ -54,12 +55,18 @@ import org.springframework.test.context.web.ServletTestExecutionListener;
*
Note: this class serves only as a convenience for extension. If you do not
- * wish for your test classes to be tied to a Spring-specific class hierarchy,
- * you may configure your own custom test classes by using
- * {@link SpringJUnit4ClassRunner}, {@link ContextConfiguration
- * @ContextConfiguration}, {@link TestExecutionListeners
- * @TestExecutionListeners}, etc.
+ *
This class serves only as a convenience for extension.
+ *
+ *
If you do not wish for your test classes to be tied to a Spring-specific
+ * class hierarchy, you may configure your own custom test classes by using
+ * {@link SpringJUnit4ClassRunner}, {@link ContextConfiguration @ContextConfiguration},
+ * {@link TestExecutionListeners @TestExecutionListeners}, etc.
+ *
If you wish to extend this class and use a runner other than the
+ * {@link SpringJUnit4ClassRunner}, as of Spring Framework 4.2 you can use
+ * {@link org.springframework.test.context.junit4.rules.SpringClassRule SpringClassRule} and
+ * {@link org.springframework.test.context.junit4.rules.SpringMethodRule SpringMethodRule}
+ * and specify your runner of choice via {@link RunWith @RunWith(...)}.
+ *
*
*
NOTE: As of Spring Framework 4.1, this class requires JUnit 4.9 or higher.
*
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.java b/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.java
index 6299311b13..01cbd861b8 100644
--- a/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.java
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/AbstractTransactionalJUnit4SpringContextTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -60,13 +60,18 @@ import org.springframework.transaction.annotation.Transactional;
*
Note: this class serves only as a convenience for extension. If you do not
- * wish for your test classes to be tied to a Spring-specific class hierarchy,
- * you may configure your own custom test classes by using
- * {@link SpringJUnit4ClassRunner}, {@link ContextConfiguration
- * @ContextConfiguration}, {@link TestExecutionListeners
- * @TestExecutionListeners}, {@link Transactional @Transactional},
- * etc.
+ *
This class serves only as a convenience for extension.
+ *
+ *
If you do not wish for your test classes to be tied to a Spring-specific
+ * class hierarchy, you may configure your own custom test classes by using
+ * {@link SpringJUnit4ClassRunner}, {@link ContextConfiguration @ContextConfiguration},
+ * {@link TestExecutionListeners @TestExecutionListeners}, etc.
+ *
If you wish to extend this class and use a runner other than the
+ * {@link SpringJUnit4ClassRunner}, as of Spring Framework 4.2 you can use
+ * {@link org.springframework.test.context.junit4.rules.SpringClassRule SpringClassRule} and
+ * {@link org.springframework.test.context.junit4.rules.SpringMethodRule SpringMethodRule}
+ * and specify your runner of choice via {@link org.junit.runner.RunWith @RunWith(...)}.
+ *
*
*
NOTE: As of Spring Framework 4.1, this class requires JUnit 4.9 or higher.
*
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java b/spring-test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java
index 547e43a29d..6762e37ca6 100644
--- a/spring-test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/SpringJUnit4ClassRunner.java
@@ -16,6 +16,7 @@
package org.springframework.test.context.junit4;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
@@ -41,6 +42,8 @@ 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.rules.SpringClassRule;
+import org.springframework.test.context.junit4.rules.SpringMethodRule;
import org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks;
import org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks;
import org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks;
@@ -72,6 +75,9 @@ import org.springframework.util.ReflectionUtils;
*
If you would like to use the Spring TestContext Framework with a runner
+ * other than this one, use {@link SpringClassRule} and {@link SpringMethodRule}.
+ *
*
NOTE: As of Spring Framework 4.1, this class requires JUnit 4.9 or higher.
*
* @author Sam Brannen
@@ -80,6 +86,8 @@ import org.springframework.util.ReflectionUtils;
* @see TestContextManager
* @see AbstractJUnit4SpringContextTests
* @see AbstractTransactionalJUnit4SpringContextTests
+ * @see org.springframework.test.context.junit4.rules.SpringClassRule
+ * @see org.springframework.test.context.junit4.rules.SpringMethodRule
*/
@SuppressWarnings("deprecation")
public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
@@ -101,6 +109,19 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
private final TestContextManager testContextManager;
+ private static void ensureSpringRulesAreNotPresent(Class> testClass) {
+ for (Field field : testClass.getFields()) {
+ if (SpringClassRule.class.isAssignableFrom(field.getType())) {
+ throw new IllegalStateException(String.format("Detected SpringClassRule field in test class [%s], but "
+ + "SpringClassRule cannot be used with the SpringJUnit4ClassRunner.", testClass.getName()));
+ }
+ if (SpringMethodRule.class.isAssignableFrom(field.getType())) {
+ throw new IllegalStateException(String.format("Detected SpringMethodRule field in test class [%s], "
+ + "but SpringMethodRule cannot be used with the SpringJUnit4ClassRunner.", testClass.getName()));
+ }
+ }
+ }
+
/**
* Construct a new {@code SpringJUnit4ClassRunner} and initialize a
* {@link TestContextManager} to provide Spring testing functionality to
@@ -113,6 +134,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
if (logger.isDebugEnabled()) {
logger.debug("SpringJUnit4ClassRunner constructor called with [" + clazz + "].");
}
+ ensureSpringRulesAreNotPresent(clazz);
this.testContextManager = createTestContextManager(clazz);
}
@@ -166,7 +188,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
/**
* Wrap the {@link Statement} returned by the parent implementation with a
- * {@link RunBeforeTestClassCallbacks} statement, thus preserving the
+ * {@code RunBeforeTestClassCallbacks} statement, thus preserving the
* default JUnit functionality while adding support for the Spring TestContext
* Framework.
* @see RunBeforeTestClassCallbacks
@@ -179,7 +201,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
/**
* Wrap the {@link Statement} returned by the parent implementation with a
- * {@link RunAfterTestClassCallbacks} statement, thus preserving the default
+ * {@code RunAfterTestClassCallbacks} statement, thus preserving the default
* JUnit functionality while adding support for the Spring TestContext Framework.
* @see RunAfterTestClassCallbacks
*/
@@ -393,7 +415,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
/**
* Wrap the {@link Statement} returned by the parent implementation with a
- * {@link RunBeforeTestMethodCallbacks} statement, thus preserving the
+ * {@code RunBeforeTestMethodCallbacks} statement, thus preserving the
* default functionality while adding support for the Spring TestContext
* Framework.
* @see RunBeforeTestMethodCallbacks
@@ -407,7 +429,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
/**
* Wrap the {@link Statement} returned by the parent implementation with a
- * {@link RunAfterTestMethodCallbacks} statement, thus preserving the
+ * {@code RunAfterTestMethodCallbacks} statement, thus preserving the
* default functionality while adding support for the Spring TestContext
* Framework.
* @see RunAfterTestMethodCallbacks
@@ -423,10 +445,10 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
* Return a {@link Statement} that potentially repeats the execution of
* the {@code next} statement.
*
Supports Spring's {@link Repeat @Repeat} annotation by returning a
- * {@link SpringRepeat} statement initialized with the configured repeat
+ * {@code SpringRepeat} statement initialized with the configured repeat
* count (if greater than {@code 1}); otherwise, the supplied statement
* is returned unmodified.
- * @return either a {@link SpringRepeat} or the supplied {@link Statement}
+ * @return either a {@code SpringRepeat} or the supplied {@code Statement}
* as appropriate
* @see SpringRepeat
*/
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringClassRule.java b/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringClassRule.java
new file mode 100644
index 0000000000..c57986cece
--- /dev/null
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringClassRule.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2002-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.rules;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import org.springframework.test.context.TestContextManager;
+import org.springframework.test.context.junit4.statements.ProfileValueChecker;
+import org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks;
+import org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks;
+
+/**
+ * {@code SpringClassRule} is a custom JUnit {@link TestRule} that provides
+ * class-level functionality of the Spring TestContext Framework
+ * to standard JUnit tests by means of the {@link TestContextManager} and associated
+ * support classes and annotations.
+ *
+ *
In contrast to the {@link org.springframework.test.context.junit4.SpringJUnit4ClassRunner
+ * SpringJUnit4ClassRunner}, Spring's rule-based JUnit support has the advantage
+ * that it is independent of any {@link org.junit.runner.Runner Runner} and
+ * can therefore be combined with existing alternative runners like JUnit's
+ * {@code Parameterized} or third-party runners such as the {@code MockitoJUnitRunner}.
+ *
+ *
In order to achieve the same functionality as the {@code SpringJUnit4ClassRunner},
+ * however, a {@code SpringClassRule} must be combined with a {@link SpringMethodRule},
+ * since {@code SpringClassRule} only provides the class-level features of the
+ * {@code SpringJUnit4ClassRunner}.
+ *
+ *
Example Usage
+ *
public class ExampleSpringIntegrationTest {
+ *
+ * @ClassRule
+ * public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
+ *
+ * @Rule
+ * public final SpringMethodRule springMethodRule = new SpringMethodRule(this);
+ *
+ * // ...
+ * }
+ *
+ *
The following list constitutes all annotations currently supported directly
+ * or indirectly by {@code SpringClassRule}. (Note that additional annotations
+ * may be supported by various
+ * {@link org.springframework.test.context.TestExecutionListener TestExecutionListener} or
+ * {@link org.springframework.test.context.TestContextBootstrapper TestContextBootstrapper}
+ * implementations.)
+ *
+ *
NOTE: This class requires JUnit 4.9 or higher.
+ *
+ * @author Sam Brannen
+ * @author Philippe Marschall
+ * @since 4.2
+ * @see #apply(Statement, Description)
+ * @see SpringMethodRule
+ * @see org.springframework.test.context.TestContextManager
+ * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
+ */
+public class SpringClassRule implements TestRule {
+
+ private static final Log logger = LogFactory.getLog(SpringClassRule.class);
+
+ /**
+ * This field is {@code volatile} since a {@code SpringMethodRule} can
+ * potentially access it from a different thread, depending on the type
+ * of JUnit runner in use.
+ */
+ private volatile TestContextManager testContextManager;
+
+
+ /**
+ * Create a new {@link TestContextManager} for the supplied test class.
+ *
Can be overridden by subclasses.
+ * @param clazz the test class to be managed
+ */
+ protected TestContextManager createTestContextManager(Class> clazz) {
+ return new TestContextManager(clazz);
+ }
+
+ /**
+ * Get the {@link TestContextManager} associated with this rule.
+ *
Will be {@code null} until the {@link #apply} method is invoked
+ * by a JUnit runner.
+ */
+ protected final TestContextManager getTestContextManager() {
+ return this.testContextManager;
+ }
+
+ /**
+ * Apply class-level functionality of the Spring TestContext
+ * Framework to the supplied {@code base} statement.
+ *
+ *
Specifically, this method creates the {@link TestContextManager} used
+ * by this rule and its associated {@link SpringMethodRule} and invokes the
+ * {@link TestContextManager#beforeTestClass() beforeTestClass()} and
+ * {@link TestContextManager#afterTestClass() afterTestClass()} methods
+ * on the {@code TestContextManager}.
+ *
+ *
In addition, this method checks whether the test is enabled in
+ * the current execution environment. This prevents classes with a
+ * non-matching {@code @IfProfileValue} annotation from running altogether,
+ * even skipping the execution of {@code beforeTestClass()} methods
+ * in {@code TestExecutionListeners}.
+ *
+ * @param base the base {@code Statement} that this rule should be applied to
+ * @param description a {@code Description} of the current test execution
+ * @return a statement that wraps the supplied {@code base} with class-level
+ * functionality of the Spring TestContext Framework
+ * @see #createTestContextManager
+ * @see #withBeforeTestClassCallbacks
+ * @see #withAfterTestClassCallbacks
+ * @see #withProfileValueCheck
+ */
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ Class> testClass = description.getTestClass();
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Applying SpringClassRule to test class [" + testClass.getName() + "].");
+ }
+
+ validateSpringMethodRuleConfiguration(testClass);
+
+ this.testContextManager = createTestContextManager(testClass);
+
+ Statement statement = base;
+ statement = withBeforeTestClassCallbacks(statement);
+ statement = withAfterTestClassCallbacks(statement);
+ statement = withProfileValueCheck(testClass, statement);
+ return statement;
+ }
+
+ /**
+ * Wrap the supplied {@code statement} with a {@code RunBeforeTestClassCallbacks} statement.
+ * @see RunBeforeTestClassCallbacks
+ */
+ protected Statement withBeforeTestClassCallbacks(Statement statement) {
+ return new RunBeforeTestClassCallbacks(statement, getTestContextManager());
+ }
+
+ /**
+ * Wrap the supplied {@code statement} with a {@code RunAfterTestClassCallbacks} statement.
+ * @see RunAfterTestClassCallbacks
+ */
+ protected Statement withAfterTestClassCallbacks(Statement statement) {
+ return new RunAfterTestClassCallbacks(statement, getTestContextManager());
+ }
+
+ /**
+ * Wrap the supplied {@code statement} with a {@code ProfileValueChecker} statement.
+ * @see ProfileValueChecker
+ */
+ protected Statement withProfileValueCheck(Class> testClass, Statement statement) {
+ return new ProfileValueChecker(statement, testClass, null);
+ }
+
+ private void validateSpringMethodRuleConfiguration(Class> testClass) {
+ Field ruleField = null;
+
+ for (Field field : testClass.getFields()) {
+ int modifiers = field.getModifiers();
+ if (!Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)
+ && (SpringMethodRule.class.isAssignableFrom(field.getType()))) {
+ ruleField = field;
+ break;
+ }
+ }
+
+ if (ruleField == null) {
+ throw new IllegalStateException(String.format(
+ "Failed to find 'public SpringMethodRule' field in test class [%s]. "
+ + "Consult the Javadoc for SpringClassRule for details.", testClass.getName()));
+ }
+
+ if (!ruleField.isAnnotationPresent(Rule.class)) {
+ throw new IllegalStateException(String.format(
+ "SpringMethodRule field [%s] must be annotated with JUnit's @Rule annotation. "
+ + "Consult the Javadoc for SpringClassRule for details.", ruleField));
+ }
+ }
+
+}
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringMethodRule.java b/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringMethodRule.java
new file mode 100644
index 0000000000..7f9dbc1a64
--- /dev/null
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/rules/SpringMethodRule.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2002-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.rules;
+
+import java.lang.reflect.Field;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.junit.ClassRule;
+import org.junit.rules.MethodRule;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.annotation.AnnotationAttributes;
+import org.springframework.core.annotation.AnnotationUtils;
+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.ProfileValueChecker;
+import org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks;
+import org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks;
+import org.springframework.test.context.junit4.statements.RunPrepareTestInstanceCallbacks;
+import org.springframework.test.context.junit4.statements.SpringFailOnTimeout;
+import org.springframework.test.context.junit4.statements.SpringRepeat;
+import org.springframework.util.Assert;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * {@code SpringMethodRule} is a custom JUnit {@link MethodRule} that
+ * provides instance-level and method-level functionality of the
+ * Spring TestContext Framework to standard JUnit tests by means
+ * of the {@link TestContextManager} and associated support classes and
+ * annotations.
+ *
+ *
In contrast to the {@link org.springframework.test.context.junit4.SpringJUnit4ClassRunner
+ * SpringJUnit4ClassRunner}, Spring's rule-based JUnit support has the advantage
+ * that it is independent of any {@link org.junit.runner.Runner Runner} and
+ * can therefore be combined with existing alternative runners like JUnit's
+ * {@code Parameterized} or third-party runners such as the {@code MockitoJUnitRunner}.
+ *
+ *
In order to achieve the same functionality as the {@code SpringJUnit4ClassRunner},
+ * however, a {@code SpringMethodRule} must be combined with a {@link SpringClassRule},
+ * since {@code SpringMethodRule} only provides the method-level features of the
+ * {@code SpringJUnit4ClassRunner}.
+ *
+ *
Example Usage
+ *
public class ExampleSpringIntegrationTest {
+ *
+ * @ClassRule
+ * public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
+ *
+ * @Rule
+ * public final SpringMethodRule springMethodRule = new SpringMethodRule(this);
+ *
+ * // ...
+ * }
+ *
+ *
The following list constitutes all annotations currently supported directly
+ * or indirectly by {@code SpringMethodRule}. (Note that additional annotations
+ * may be supported by various
+ * {@link org.springframework.test.context.TestExecutionListener TestExecutionListener} or
+ * {@link org.springframework.test.context.TestContextBootstrapper TestContextBootstrapper}
+ * implementations.)
+ *
+ *
NOTE: This class requires JUnit 4.9 or higher.
+ *
+ * @author Sam Brannen
+ * @author Philippe Marschall
+ * @since 4.2
+ * @see #apply(Statement, FrameworkMethod, Object)
+ * @see SpringClassRule
+ * @see org.springframework.test.context.TestContextManager
+ * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
+ */
+public class SpringMethodRule implements MethodRule {
+
+ private static final Log logger = LogFactory.getLog(SpringMethodRule.class);
+
+ /**
+ * {@code SpringMethodRule} retains a reference to the {@code SpringClassRule}
+ * instead of the {@code TestContextManager}, since the class rule owns
+ * the {@code TestContextManager}.
+ */
+ private final SpringClassRule springClassRule;
+
+
+ /**
+ * Construct a new {@code SpringMethodRule} for the supplied test instance.
+ *
+ *
The test class must declare a {@code public static final SpringClassRule}
+ * field (i.e., a constant) that is annotated with JUnit's
+ * {@link ClassRule @ClassRule} — for example:
+ *
+ *
@ClassRule
+ * public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
+ *
+ * @param testInstance the test instance, never {@code null}
+ * @throws IllegalStateException if the test class does not declare an
+ * appropriate {@code SpringClassRule} constant.
+ */
+ public SpringMethodRule(Object testInstance) {
+ Assert.notNull(testInstance, "testInstance must not be null");
+ this.springClassRule = retrieveAndValidateSpringClassRule(testInstance.getClass());
+ }
+
+ /**
+ * Apply instance-level and method-level functionality
+ * of the Spring TestContext Framework to the supplied {@code base}
+ * statement.
+ *
+ *
Specifically, this method invokes the
+ * {@link TestContextManager#prepareTestInstance prepareTestInstance()},
+ * {@link TestContextManager#beforeTestMethod beforeTestMethod()}, and
+ * {@link TestContextManager#afterTestMethod afterTestMethod()} methods
+ * on the {@code TestContextManager}, potentially with Spring timeouts
+ * and repetitions.
+ *
+ *
In addition, this method checks whether the test is enabled in
+ * the current execution environment. This prevents methods with a
+ * non-matching {@code @IfProfileValue} annotation from running altogether,
+ * even skipping the execution of {@code prepareTestInstance()} methods
+ * in {@code TestExecutionListeners}.
+ *
+ * @param base the base {@code Statement} that this rule should be applied to
+ * @param frameworkMethod the method which is about to be invoked on the test instance
+ * @param testInstance the current test instance
+ * @return a statement that wraps the supplied {@code base} with instance-level
+ * and method-level functionality of the Spring TestContext Framework
+ * @see #withBeforeTestMethodCallbacks
+ * @see #withAfterTestMethodCallbacks
+ * @see #withPotentialRepeat
+ * @see #withPotentialTimeout
+ * @see #withTestInstancePreparation
+ * @see #withProfileValueCheck
+ */
+ @Override
+ public Statement apply(final Statement base, final FrameworkMethod frameworkMethod, final Object testInstance) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Applying SpringMethodRule to test method [" + frameworkMethod.getMethod() + "].");
+ }
+
+ Statement statement = base;
+ statement = withBeforeTestMethodCallbacks(frameworkMethod, testInstance, statement);
+ statement = withAfterTestMethodCallbacks(frameworkMethod, testInstance, statement);
+ statement = withTestInstancePreparation(testInstance, statement);
+ statement = withPotentialRepeat(frameworkMethod, testInstance, statement);
+ statement = withPotentialTimeout(frameworkMethod, testInstance, statement);
+ statement = withProfileValueCheck(frameworkMethod, testInstance, statement);
+ return statement;
+ }
+
+ /**
+ * Get the {@link TestContextManager} associated with this rule.
+ */
+ protected final TestContextManager getTestContextManager() {
+ return this.springClassRule.getTestContextManager();
+ }
+
+ /**
+ * Wrap the supplied {@link Statement} with a {@code ProfileValueChecker} statement.
+ * @see ProfileValueChecker
+ */
+ protected Statement withProfileValueCheck(FrameworkMethod frameworkMethod, Object testInstance, Statement statement) {
+ return new ProfileValueChecker(statement, testInstance.getClass(), frameworkMethod.getMethod());
+ }
+
+ /**
+ * Wrap the supplied {@link Statement} with a {@code RunPrepareTestInstanceCallbacks} statement.
+ * @see RunPrepareTestInstanceCallbacks
+ */
+ protected Statement withTestInstancePreparation(Object testInstance, Statement statement) {
+ return new RunPrepareTestInstanceCallbacks(statement, testInstance, getTestContextManager());
+ }
+
+ /**
+ * Wrap the supplied {@link Statement} with a {@code RunBeforeTestMethodCallbacks} statement.
+ * @see RunBeforeTestMethodCallbacks
+ */
+ protected Statement withBeforeTestMethodCallbacks(FrameworkMethod frameworkMethod, Object testInstance,
+ Statement statement) {
+ return new RunBeforeTestMethodCallbacks(statement, testInstance, frameworkMethod.getMethod(),
+ getTestContextManager());
+ }
+
+ /**
+ * Wrap the supplied {@link Statement} with a {@code RunAfterTestMethodCallbacks} statement.
+ * @see RunAfterTestMethodCallbacks
+ */
+ protected Statement withAfterTestMethodCallbacks(FrameworkMethod frameworkMethod, Object testInstance,
+ Statement statement) {
+ return new RunAfterTestMethodCallbacks(statement, testInstance, frameworkMethod.getMethod(),
+ getTestContextManager());
+ }
+
+ /**
+ * Return a {@link Statement} that potentially repeats the execution of
+ * the {@code next} statement.
+ *
Supports Spring's {@link Repeat @Repeat} annotation by returning a
+ * {@link SpringRepeat} statement initialized with the configured repeat
+ * count (if greater than {@code 1}); otherwise, the supplied statement
+ * is returned unmodified.
+ * @return either a {@code SpringRepeat} or the supplied {@code Statement}
+ * @see SpringRepeat
+ */
+ protected Statement withPotentialRepeat(FrameworkMethod frameworkMethod, Object testInstance, Statement next) {
+ Repeat repeatAnnotation = AnnotationUtils.getAnnotation(frameworkMethod.getMethod(), Repeat.class);
+ int repeat = (repeatAnnotation != null ? repeatAnnotation.value() : 1);
+ return (repeat > 1 ? new SpringRepeat(next, frameworkMethod.getMethod(), repeat) : next);
+ }
+
+ /**
+ * Return a {@link Statement} that potentially throws an exception if
+ * the {@code next} statement in the execution chain takes longer than
+ * a specified timeout.
+ *
Supports Spring's {@link Timed @Timed} annotation by returning a
+ * {@link SpringFailOnTimeout} statement initialized with the configured
+ * timeout (if greater than {@code 0}); otherwise, the supplied statement
+ * is returned unmodified.
+ * @return either a {@code SpringFailOnTimeout} or the supplied {@code Statement}
+ * @see #getSpringTimeout(FrameworkMethod)
+ * @see SpringFailOnTimeout
+ */
+ protected Statement withPotentialTimeout(FrameworkMethod frameworkMethod, Object testInstance, Statement next) {
+ long springTimeout = getSpringTimeout(frameworkMethod);
+ return (springTimeout > 0 ? new SpringFailOnTimeout(next, springTimeout) : next);
+ }
+
+ /**
+ * Retrieve the configured Spring-specific {@code timeout} from the
+ * {@link Timed @Timed} annotation on the supplied
+ * {@linkplain FrameworkMethod test method}.
+ * @return the timeout, or {@code 0} if none was specified
+ */
+ protected long getSpringTimeout(FrameworkMethod frameworkMethod) {
+ AnnotationAttributes annAttrs = AnnotatedElementUtils.findAnnotationAttributes(frameworkMethod.getMethod(),
+ Timed.class.getName());
+ if (annAttrs == null) {
+ return 0;
+ }
+ else {
+ long millis = annAttrs. getNumber("millis").longValue();
+ return millis > 0 ? millis : 0;
+ }
+ }
+
+ private static SpringClassRule retrieveAndValidateSpringClassRule(Class> testClass) {
+ Field springClassRuleField = null;
+
+ for (Field field : testClass.getFields()) {
+ if (ReflectionUtils.isPublicStaticFinal(field) && (SpringClassRule.class.isAssignableFrom(field.getType()))) {
+ springClassRuleField = field;
+ break;
+ }
+ }
+
+ if (springClassRuleField == null) {
+ throw new IllegalStateException(String.format(
+ "Failed to find 'public static final SpringClassRule' field in test class [%s]. "
+ + "Consult the Javadoc for SpringClassRule for details.", testClass.getName()));
+ }
+
+ if (!springClassRuleField.isAnnotationPresent(ClassRule.class)) {
+ throw new IllegalStateException(String.format(
+ "SpringClassRule field [%s] must be annotated with JUnit's @ClassRule annotation. "
+ + "Consult the Javadoc for SpringClassRule for details.", springClassRuleField));
+ }
+
+ return (SpringClassRule) ReflectionUtils.getField(springClassRuleField, null);
+ }
+
+}
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/rules/package-info.java b/spring-test/src/main/java/org/springframework/test/context/junit4/rules/package-info.java
new file mode 100644
index 0000000000..16124c162d
--- /dev/null
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/rules/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Custom JUnit {@code Rules} used in the Spring TestContext Framework.
+ */
+package org.springframework.test.context.junit4.rules;
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/ProfileValueChecker.java b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/ProfileValueChecker.java
new file mode 100644
index 0000000000..83861e44e6
--- /dev/null
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/ProfileValueChecker.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2002-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.lang.reflect.Method;
+
+import org.junit.Assume;
+import org.junit.runners.model.Statement;
+
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.test.annotation.IfProfileValue;
+import org.springframework.test.annotation.ProfileValueUtils;
+import org.springframework.util.Assert;
+
+/**
+ * {@code ProfileValueChecker} is a custom JUnit {@link Statement} that checks
+ * whether a test class or test method is enabled in the current environment
+ * via Spring's {@link IfProfileValue @IfProfileValue} annotation.
+ *
+ * @author Sam Brannen
+ * @author Philippe Marschall
+ * @since 4.2
+ * @see #evaluate()
+ * @see IfProfileValue
+ * @see ProfileValueUtils
+ */
+public class ProfileValueChecker extends Statement {
+
+ private final Statement next;
+
+ private final Class> testClass;
+
+ private final Method testMethod;
+
+
+ /**
+ * Construct a new {@code ProfileValueChecker} statement.
+ *
+ * @param next the next {@code Statement} in the execution chain; never
+ * {@code null}
+ * @param testClass the test class to check; never {@code null}
+ * @param testMethod the test method to check; may be {@code null} if
+ * this {@code ProfileValueChecker} is being applied at the class level
+ */
+ public ProfileValueChecker(Statement next, Class> testClass, Method testMethod) {
+ Assert.notNull(next, "The next statement must not be null");
+ Assert.notNull(testClass, "The test class must not be null");
+ this.next = next;
+ this.testClass = testClass;
+ this.testMethod = testMethod;
+ }
+
+ /**
+ * Determine if the test specified by arguments to the
+ * {@linkplain #ProfileValueChecker constructor} is enabled in
+ * the current environment, as configured via the {@link IfProfileValue
+ * @IfProfileValue} annotation.
+ *
If the test is not annotated with {@code @IfProfileValue} it is
+ * considered enabled.
+ *
If a test is not enabled, this method will abort further evaluation
+ * of the execution chain with a failed assumption; otherwise, this method
+ * will simply evaluate the next {@link Statement} in the execution chain.
+ * @see ProfileValueUtils#isTestEnabledInThisEnvironment(Class)
+ * @see ProfileValueUtils#isTestEnabledInThisEnvironment(Method, Class)
+ * @see org.junit.Assume
+ */
+ @Override
+ public void evaluate() throws Throwable {
+ if (this.testMethod == null) {
+ if (!ProfileValueUtils.isTestEnabledInThisEnvironment(testClass)) {
+ // Invoke assumeTrue() with false to avoid direct reference to JUnit's
+ // AssumptionViolatedException which exists in two packages as of JUnit 4.12.
+ Assume.assumeTrue(String.format(
+ "Profile configured via [%s] is not enabled in this environment for test class [%s].",
+ AnnotationUtils.findAnnotation(testClass, IfProfileValue.class), testClass.getName()), false);
+ }
+ }
+ else {
+ if (!ProfileValueUtils.isTestEnabledInThisEnvironment(testMethod, testClass)) {
+ // Invoke assumeTrue() with false to avoid direct reference to JUnit's
+ // AssumptionViolatedException which exists in two packages as of JUnit 4.12.
+ Assume.assumeTrue(String.format(
+ "Profile configured via @IfProfileValue is not enabled in this environment for test method [%s].",
+ testMethod), false);
+ }
+ }
+
+ this.next.evaluate();
+ }
+
+}
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestClassCallbacks.java b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestClassCallbacks.java
index f9e9261e3e..af2b699a2a 100644
--- a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestClassCallbacks.java
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestClassCallbacks.java
@@ -25,13 +25,15 @@ import org.junit.runners.model.Statement;
import org.springframework.test.context.TestContextManager;
/**
- * {@code RunAfterTestClassCallbacks} is a custom JUnit {@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
+ * {@code RunAfterTestClassCallbacks} is a custom JUnit {@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}.
*
+ *
NOTE: This class requires JUnit 4.9 or higher.
+ *
* @see #evaluate()
- * @see RunBeforeTestMethodCallbacks
+ * @see RunBeforeTestClassCallbacks
* @author Sam Brannen
* @since 3.0
*/
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestMethodCallbacks.java b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestMethodCallbacks.java
index 68408b2746..b296b3a939 100644
--- a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestMethodCallbacks.java
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunAfterTestMethodCallbacks.java
@@ -28,8 +28,10 @@ import org.springframework.test.context.TestContextManager;
/**
* {@code RunAfterTestMethodCallbacks} is a custom JUnit {@link Statement} which allows
* the Spring TestContext Framework to be plugged into the JUnit execution chain
- * by calling {@link TestContextManager#afterTestMethod(Object, Method, Throwable)
- * afterTestMethod()} on the supplied {@link TestContextManager}.
+ * by calling {@link TestContextManager#afterTestMethod afterTestMethod()} on the supplied
+ * {@link TestContextManager}.
+ *
+ *
NOTE: This class requires JUnit 4.9 or higher.
*
* @see #evaluate()
* @see RunBeforeTestMethodCallbacks
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunPrepareTestInstanceCallbacks.java b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunPrepareTestInstanceCallbacks.java
new file mode 100644
index 0000000000..87c2824528
--- /dev/null
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/RunPrepareTestInstanceCallbacks.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2002-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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 RunPrepareTestInstanceCallbacks} is a custom JUnit {@link Statement} which
+ * allows the Spring TestContext Framework to be plugged into the JUnit
+ * execution chain by calling {@link TestContextManager#prepareTestInstance(Object)
+ * prepareTestInstance()} on the supplied {@link TestContextManager}.
+ *
+ * @see #evaluate()
+ * @author Sam Brannen
+ * @since 4.2
+ */
+public class RunPrepareTestInstanceCallbacks extends Statement {
+
+ private final Statement next;
+
+ private final Object testInstance;
+
+ private final TestContextManager testContextManager;
+
+
+ /**
+ * Construct a new {@code RunPrepareTestInstanceCallbacks} statement.
+ *
+ * @param next the next {@code Statement} in the execution chain; never {@code null}
+ * @param testInstance the current test instance; never {@code null}
+ * @param testContextManager the {@code TestContextManager} upon which to call
+ * {@code prepareTestInstance()}; never {@code null}
+ */
+ public RunPrepareTestInstanceCallbacks(Statement next, Object testInstance, TestContextManager testContextManager) {
+ this.next = next;
+ this.testInstance = testInstance;
+ this.testContextManager = testContextManager;
+ }
+
+ /**
+ * Invoke {@link TestContextManager#prepareTestInstance(Object)} and
+ * then evaluate the next {@link Statement} in the execution chain
+ * (typically an instance of {@link RunAfterTestMethodCallbacks}).
+ */
+ @Override
+ public void evaluate() throws Throwable {
+ this.testContextManager.prepareTestInstance(testInstance);
+ this.next.evaluate();
+ }
+
+}
diff --git a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/SpringFailOnTimeout.java b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/SpringFailOnTimeout.java
index def818bc98..b12646ab28 100644
--- a/spring-test/src/main/java/org/springframework/test/context/junit4/statements/SpringFailOnTimeout.java
+++ b/spring-test/src/main/java/org/springframework/test/context/junit4/statements/SpringFailOnTimeout.java
@@ -28,6 +28,11 @@ import org.springframework.test.annotation.Timed;
* if the next statement in the execution chain takes more than the specified
* number of milliseconds.
*
+ *
In contrast to JUnit's
+ * {@link org.junit.internal.runners.statements.FailOnTimeout FailOnTimeout},
+ * the next {@code statement} will be executed in the same thread as the
+ * caller and will therefore not be aborted preemptively.
+ *
* @see #evaluate()
* @author Sam Brannen
* @since 3.0
@@ -53,11 +58,9 @@ public class SpringFailOnTimeout extends Statement {
/**
* Evaluate the next {@link Statement statement} in the execution chain
- * (typically an instance of
- * {@link org.junit.internal.runners.statements.InvokeMethod InvokeMethod}
- * or {@link org.junit.internal.runners.statements.ExpectException
- * ExpectException}) and throw a {@link TimeoutException} if the next
- * {@code statement} executes longer than the specified {@code timeout}.
+ * (typically an instance of {@link SpringRepeat}) and throw a
+ * {@link TimeoutException} if the next {@code statement} executes longer
+ * than the specified {@code timeout}.
*/
@Override
public void evaluate() throws Throwable {
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.java
index fc06f6b272..500ab69331 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/AbsolutePathSpringJUnit4ClassRunnerAppCtxTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 the original author or authors.
+ * Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,6 @@
package org.springframework.test.context.junit4;
-import org.junit.runner.RunWith;
-
import org.springframework.test.context.ContextConfiguration;
/**
@@ -31,7 +29,6 @@ import org.springframework.test.context.ContextConfiguration;
* @see ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests
* @see RelativePathSpringJUnit4ClassRunnerAppCtxTests
*/
-@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { SpringJUnit4ClassRunnerAppCtxTests.DEFAULT_CONTEXT_RESOURCE_PATH }, inheritLocations = false)
public class AbsolutePathSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests {
/* all tests are in the parent class. */
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests.java
index 4b48cd2dbc..9309092107 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/BeforeAndAfterTransactionAnnotationTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,10 +19,13 @@ package org.springframework.test.context.junit4;
import javax.annotation.Resource;
import javax.sql.DataSource;
+import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -56,6 +59,9 @@ public class BeforeAndAfterTransactionAnnotationTests extends AbstractTransactio
protected boolean inTransaction = false;
+ @Rule
+ public final TestName testName = new TestName();
+
@BeforeClass
public static void beforeClass() {
@@ -94,10 +100,21 @@ public class BeforeAndAfterTransactionAnnotationTests extends AbstractTransactio
@Before
public void before() {
+ assertShouldBeInTransaction();
assertEquals("Verifying the number of rows in the person table before a test method.", (this.inTransaction ? 1
: 0), countRowsInPersonTable(jdbcTemplate));
}
+ private void assertShouldBeInTransaction() {
+ boolean shouldBeInTransaction = !testName.getMethodName().equals("nonTransactionalMethod");
+ assertInTransaction(shouldBeInTransaction);
+ }
+
+ @After
+ public void after() {
+ assertShouldBeInTransaction();
+ }
+
@Test
@Transactional
public void transactionalMethod1() {
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.java
index 4bb3fb5bfa..dfe209437c 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.java
@@ -16,8 +16,6 @@
package org.springframework.test.context.junit4;
-import org.junit.runner.RunWith;
-
import org.springframework.test.context.ContextConfiguration;
import org.springframework.util.ResourceUtils;
@@ -33,7 +31,6 @@ import org.springframework.util.ResourceUtils;
* @see AbsolutePathSpringJUnit4ClassRunnerAppCtxTests
* @see RelativePathSpringJUnit4ClassRunnerAppCtxTests
*/
-@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests.CLASSPATH_CONTEXT_RESOURCE_PATH })
public class ClassPathResourceSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests {
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/ExpectedExceptionSpringRunnerTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/ExpectedExceptionSpringRunnerTests.java
index 8452c3c1fc..b962ad1980 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/ExpectedExceptionSpringRunnerTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/ExpectedExceptionSpringRunnerTests.java
@@ -43,23 +43,19 @@ public class ExpectedExceptionSpringRunnerTests {
@Test
public void expectedExceptions() throws Exception {
- Class testClass = ExpectedExceptionSpringRunnerTestCase.class;
+ Class> testClass = ExpectedExceptionSpringRunnerTestCase.class;
TrackingRunListener listener = new TrackingRunListener();
RunNotifier notifier = new RunNotifier();
notifier.addListener(listener);
new SpringJUnit4ClassRunner(testClass).run(notifier);
- assertEquals("Verifying number of failures for test class [" + testClass + "].", 0,
- listener.getTestFailureCount());
- assertEquals("Verifying number of tests started for test class [" + testClass + "].", 1,
- listener.getTestStartedCount());
- assertEquals("Verifying number of tests finished for test class [" + testClass + "].", 1,
- listener.getTestFinishedCount());
+ assertEquals("failures for test class [" + testClass + "].", 0, listener.getTestFailureCount());
+ assertEquals("tests started for test class [" + testClass + "].", 1, listener.getTestStartedCount());
+ assertEquals("tests finished for test class [" + testClass + "].", 1, listener.getTestFinishedCount());
}
@Ignore("TestCase classes are run manually by the enclosing test class")
- @RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({})
public static final class ExpectedExceptionSpringRunnerTestCase {
diff --git a/spring-test/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsJUnitTests.java b/spring-test/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsJUnitTests.java
index 779f929894..d227864159 100644
--- a/spring-test/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsJUnitTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/junit4/FailingBeforeAndAfterMethodsJUnitTests.java
@@ -16,16 +16,17 @@
package org.springframework.test.context.junit4;
-import java.util.Arrays;
-import java.util.Collection;
+import java.lang.reflect.Constructor;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
+import org.springframework.beans.BeanUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.TestExecutionListener;
@@ -33,30 +34,26 @@ import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springframework.test.context.transaction.AfterTransaction;
import org.springframework.test.context.transaction.BeforeTransaction;
+import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ClassUtils;
import static org.junit.Assert.*;
/**
- *
* JUnit 4 based integration test for verifying that 'before' and 'after'
* methods of {@link TestExecutionListener TestExecutionListeners} as well as
* {@link BeforeTransaction @BeforeTransaction} and
* {@link AfterTransaction @AfterTransaction} methods can fail a test in a
- * JUnit 4.4 environment, as requested in SPR-3960.
- *
- *
- * Indirectly, this class also verifies that all {@link TestExecutionListener}
+ * JUnit environment, as requested in
+ * SPR-3960.
+ *
+ *
Indirectly, this class also verifies that all {@link TestExecutionListener}
* lifecycle callbacks are called.
- *
- *
- * As of Spring 3.0, this class also tests support for the new
+ *
+ *
As of Spring 3.0, this class also tests support for the new
* {@link TestExecutionListener#beforeTestClass(TestContext) beforeTestClass()}
* and {@link TestExecutionListener#afterTestClass(TestContext)
* afterTestClass()} lifecycle callback methods.
- *
*
* @author Sam Brannen
* @since 2.5
@@ -68,38 +65,42 @@ public class FailingBeforeAndAfterMethodsJUnitTests {
@Parameters(name = "{0}")
- public static Collection