Introduce JUnit Rule alternative to SpringJUnit4ClassRunner
Since Spring Framework 2.5, support for integrating the Spring TestContext Framework (TCF) into JUnit 4 based tests has been provided via the SpringJUnit4ClassRunner, but this approach precludes the ability for tests to be run with alternative runners like JUnit's Parameterized or third-party runners such as the MockitoJUnitRunner. This commit remedies this situation by introducing @ClassRule and @Rule based alternatives to the SpringJUnit4ClassRunner. These rules are independent of any Runner and can therefore be combined with alternative runners. Due to the limitations of JUnit's implementation of rules, as of JUnit 4.12 it is currently impossible to create a single rule that can be applied both at the class level and at the method level (with access to the test instance). Consequently, this commit introduces the following two rules that must be used together. - SpringClassRule: a JUnit TestRule that provides the class-level functionality of the TCF to JUnit-based tests - SpringMethodRule: a JUnit MethodRule that provides the instance-level and method-level functionality of the TCF to JUnit-based tests In addition, this commit also introduces the following new JUnit Statements for use with rules: - RunPrepareTestInstanceCallbacks - ProfileValueChecker Issue: SPR-7731
This commit is contained in:
@@ -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 <strong>JUnit</strong> environment.
|
||||
*
|
||||
* <p>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}. <em>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.</em>
|
||||
*
|
||||
@@ -54,12 +55,18 @@ import org.springframework.test.context.web.ServletTestExecutionListener;
|
||||
* <li>{@link org.springframework.test.context.support.DirtiesContextTestExecutionListener}
|
||||
* </ul>
|
||||
*
|
||||
* <p>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.
|
||||
* <p>This class serves only as a convenience for extension.
|
||||
* <ul>
|
||||
* <li>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.</li>
|
||||
* <li>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(...)}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><strong>NOTE:</strong> As of Spring Framework 4.1, this class requires JUnit 4.9 or higher.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
* <li>{@link org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener}
|
||||
* </ul>
|
||||
*
|
||||
* <p>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.
|
||||
* <p>This class serves only as a convenience for extension.
|
||||
* <ul>
|
||||
* <li>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.</li>
|
||||
* <li>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(...)}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><strong>NOTE:</strong> As of Spring Framework 4.1, this class requires JUnit 4.9 or higher.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
* <li>{@link org.springframework.test.annotation.IfProfileValue @IfProfileValue}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>If you would like to use the Spring TestContext Framework with a runner
|
||||
* other than this one, use {@link SpringClassRule} and {@link SpringMethodRule}.
|
||||
*
|
||||
* <p><strong>NOTE:</strong> 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.
|
||||
* <p>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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
* <em>class-level</em> functionality of the <em>Spring TestContext Framework</em>
|
||||
* to standard JUnit tests by means of the {@link TestContextManager} and associated
|
||||
* support classes and annotations.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <h3>Example Usage</h3>
|
||||
* <pre><code> public class ExampleSpringIntegrationTest {
|
||||
*
|
||||
* @ClassRule
|
||||
* public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
|
||||
*
|
||||
* @Rule
|
||||
* public final SpringMethodRule springMethodRule = new SpringMethodRule(this);
|
||||
*
|
||||
* // ...
|
||||
* }</code></pre>
|
||||
*
|
||||
* <p>The following list constitutes all annotations currently supported directly
|
||||
* or indirectly by {@code SpringClassRule}. <em>(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.)</em>
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link org.springframework.test.annotation.ProfileValueSourceConfiguration @ProfileValueSourceConfiguration}</li>
|
||||
* <li>{@link org.springframework.test.annotation.IfProfileValue @IfProfileValue}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><strong>NOTE:</strong> 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.
|
||||
* <p>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.
|
||||
* <p>Will be {@code null} until the {@link #apply} method is invoked
|
||||
* by a JUnit runner.
|
||||
*/
|
||||
protected final TestContextManager getTestContextManager() {
|
||||
return this.testContextManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply <em>class-level</em> functionality of the <em>Spring TestContext
|
||||
* Framework</em> to the supplied {@code base} statement.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <em>Spring TestContext Framework</em> to standard JUnit tests by means
|
||||
* of the {@link TestContextManager} and associated support classes and
|
||||
* annotations.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <h3>Example Usage</h3>
|
||||
* <pre><code> public class ExampleSpringIntegrationTest {
|
||||
*
|
||||
* @ClassRule
|
||||
* public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
|
||||
*
|
||||
* @Rule
|
||||
* public final SpringMethodRule springMethodRule = new SpringMethodRule(this);
|
||||
*
|
||||
* // ...
|
||||
* }</code></pre>
|
||||
*
|
||||
* <p>The following list constitutes all annotations currently supported directly
|
||||
* or indirectly by {@code SpringMethodRule}. <em>(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.)</em>
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link Timed @Timed}</li>
|
||||
* <li>{@link Repeat @Repeat}</li>
|
||||
* <li>{@link org.springframework.test.annotation.ProfileValueSourceConfiguration @ProfileValueSourceConfiguration}</li>
|
||||
* <li>{@link org.springframework.test.annotation.IfProfileValue @IfProfileValue}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><strong>NOTE:</strong> 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 <em>owns</em>
|
||||
* the {@code TestContextManager}.
|
||||
*/
|
||||
private final SpringClassRule springClassRule;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new {@code SpringMethodRule} for the supplied test instance.
|
||||
*
|
||||
* <p>The test class must declare a {@code public static final SpringClassRule}
|
||||
* field (i.e., a <em>constant</em>) that is annotated with JUnit's
|
||||
* {@link ClassRule @ClassRule} — for example:
|
||||
*
|
||||
* <pre><code> @ClassRule
|
||||
* public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();</code></pre>
|
||||
*
|
||||
* @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 <em>instance-level</em> and <em>method-level</em> functionality
|
||||
* of the <em>Spring TestContext Framework</em> to the supplied {@code base}
|
||||
* statement.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
* <p>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.
|
||||
* <p>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.<Long> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Custom JUnit {@code Rules} used in the <em>Spring TestContext Framework</em>.
|
||||
*/
|
||||
package org.springframework.test.context.junit4.rules;
|
||||
@@ -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 <em>enabled</em> in
|
||||
* the current environment, as configured via the {@link IfProfileValue
|
||||
* @IfProfileValue} annotation.
|
||||
* <p>If the test is not annotated with {@code @IfProfileValue} it is
|
||||
* considered enabled.
|
||||
* <p>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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <em>Spring TestContext Framework</em> 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 <em>Spring TestContext Framework</em> to be plugged into the JUnit execution chain
|
||||
* by calling {@link TestContextManager#afterTestClass afterTestClass()} on the supplied
|
||||
* {@link TestContextManager}.
|
||||
*
|
||||
* <p><strong>NOTE:</strong> This class requires JUnit 4.9 or higher.
|
||||
*
|
||||
* @see #evaluate()
|
||||
* @see RunBeforeTestMethodCallbacks
|
||||
* @see RunBeforeTestClassCallbacks
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
|
||||
@@ -28,8 +28,10 @@ import org.springframework.test.context.TestContextManager;
|
||||
/**
|
||||
* {@code RunAfterTestMethodCallbacks} is a custom JUnit {@link Statement} which allows
|
||||
* the <em>Spring TestContext Framework</em> to be plugged into the JUnit execution chain
|
||||
* by calling {@link TestContextManager#afterTestMethod(Object, Method, Throwable)
|
||||
* afterTestMethod()} on the supplied {@link TestContextManager}.
|
||||
* by calling {@link TestContextManager#afterTestMethod afterTestMethod()} on the supplied
|
||||
* {@link TestContextManager}.
|
||||
*
|
||||
* <p><strong>NOTE:</strong> This class requires JUnit 4.9 or higher.
|
||||
*
|
||||
* @see #evaluate()
|
||||
* @see RunBeforeTestMethodCallbacks
|
||||
|
||||
@@ -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 <em>Spring TestContext Framework</em> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
* <p>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 {
|
||||
|
||||
Reference in New Issue
Block a user