Polish SpringJUnit4ClassRunner and related support classes

This commit is contained in:
Sam Brannen 2015-05-11 13:39:22 +02:00
parent 7ea50238a6
commit d14e29a5c0
8 changed files with 113 additions and 105 deletions

View File

@ -20,6 +20,7 @@ import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.internal.runners.model.ReflectiveCallable;
@ -101,7 +102,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
/**
* Constructs a new {@code SpringJUnit4ClassRunner} and initializes a
* Construct a new {@code SpringJUnit4ClassRunner} and initialize a
* {@link TestContextManager} to provide Spring testing functionality to
* standard JUnit tests.
* @param clazz the test class to be run
@ -116,7 +117,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Creates a new {@link TestContextManager} for the supplied test class.
* Create a new {@link TestContextManager} for the supplied test class.
* <p>Can be overridden by subclasses.
* @param clazz the test class to be managed
*/
@ -132,9 +133,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Returns a description suitable for an ignored test class if the test is
* Return a description suitable for an ignored test class if the test is
* disabled via {@code @IfProfileValue} at the class-level, and
* otherwise delegates to the parent implementation.
* otherwise delegate to the parent implementation.
* @see ProfileValueUtils#isTestEnabledInThisEnvironment(Class)
*/
@Override
@ -146,10 +147,10 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Check whether the test is enabled in the first place. This prevents
* classes with a non-matching {@code @IfProfileValue} annotation from
* running altogether, even skipping the execution of
* {@code prepareTestInstance()} {@code TestExecutionListener} methods.
* Check whether the test is enabled in the current execution environment.
* <p>This prevents classes with a non-matching {@code @IfProfileValue}
* annotation from running altogether, even skipping the execution of
* {@code prepareTestInstance()} methods in {@code TestExecutionListeners}.
* @see ProfileValueUtils#isTestEnabledInThisEnvironment(Class)
* @see org.springframework.test.annotation.IfProfileValue
* @see org.springframework.test.context.TestExecutionListener
@ -164,9 +165,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Wraps the {@link Statement} returned by the parent implementation with a
* Wrap the {@link Statement} returned by the parent implementation with a
* {@link RunBeforeTestClassCallbacks} statement, thus preserving the
* default functionality but adding support for the Spring TestContext
* default JUnit functionality while adding support for the Spring TestContext
* Framework.
* @see RunBeforeTestClassCallbacks
*/
@ -177,9 +178,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Wraps the {@link Statement} returned by the parent implementation with a
* Wrap the {@link Statement} returned by the parent implementation with a
* {@link RunAfterTestClassCallbacks} statement, thus preserving the default
* functionality but adding support for the Spring TestContext Framework.
* JUnit functionality while adding support for the Spring TestContext Framework.
* @see RunAfterTestClassCallbacks
*/
@Override
@ -189,10 +190,10 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Delegates to the parent implementation for creating the test instance and
* then allows the {@link #getTestContextManager() TestContextManager} to
* Delegate to the parent implementation for creating the test instance and
* then allow the {@link #getTestContextManager() TestContextManager} to
* prepare the test instance before returning it.
* @see TestContextManager#prepareTestInstance(Object)
* @see TestContextManager#prepareTestInstance
*/
@Override
protected Object createTest() throws Exception {
@ -202,7 +203,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Performs the same logic as
* Perform the same logic as
* {@link BlockJUnit4ClassRunner#runChild(FrameworkMethod, RunNotifier)},
* except that tests are determined to be <em>ignored</em> by
* {@link #isTestMethodIgnored(FrameworkMethod)}.
@ -226,25 +227,26 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Augments the default JUnit behavior
* {@link #withPotentialRepeat(FrameworkMethod, Object, Statement) with
* potential repeats} of the entire execution chain.
* <p>Furthermore, support for timeouts has been moved down the execution chain
* in order to include execution of {@link org.junit.Before @Before}
* and {@link org.junit.After @After} methods within the timed
* execution. Note that this differs from the default JUnit behavior of
* executing {@code @Before} and {@code @After} methods
* in the main thread while executing the actual test method in a separate
* thread. Thus, the end effect is that {@code @Before} and
* {@code @After} methods will be executed in the same thread as
* the test method. As a consequence, JUnit-specified timeouts will work
* fine in combination with Spring transactions. Note that JUnit-specific
* timeouts still differ from Spring-specific timeouts in that the former
* execute in a separate thread while the latter simply execute in the main
* thread (like regular tests).
* Augment the default JUnit behavior
* {@linkplain #withPotentialRepeat with potential repeats} of the entire
* execution chain.
* <p>Furthermore, support for timeouts has been moved down the execution
* chain in order to include execution of {@link org.junit.Before @Before}
* and {@link org.junit.After @After} methods within the timed execution.
* Note that this differs from the default JUnit behavior of executing
* {@code @Before} and {@code @After} methods in the main thread while
* executing the actual test method in a separate thread. Thus, the net
* effect is that {@code @Before} and {@code @After} methods will be
* executed in the same thread as the test method. As a consequence,
* JUnit-specified timeouts will work fine in combination with Spring
* transactions. However, JUnit-specific timeouts still differ from
* Spring-specific timeouts in that the former execute in a separate
* thread while the latter simply execute in the main thread (like regular
* tests).
* @see #possiblyExpectingExceptions(FrameworkMethod, Object, Statement)
* @see #withBefores(FrameworkMethod, Object, Statement)
* @see #withAfters(FrameworkMethod, Object, Statement)
* @see #withRulesReflectively(FrameworkMethod, Object, Statement)
* @see #withPotentialRepeat(FrameworkMethod, Object, Statement)
* @see #withPotentialTimeout(FrameworkMethod, Object, Statement)
*/
@ -283,9 +285,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Returns {@code true} if {@link Ignore @Ignore} is present for the supplied
* {@link FrameworkMethod test method} or if the test method is disabled via
* {@code @IfProfileValue}.
* Return {@code true} if {@link Ignore @Ignore} is present for the supplied
* {@linkplain FrameworkMethod test method} or if the test method is disabled
* via {@code @IfProfileValue}.
* @see ProfileValueUtils#isTestEnabledInThisEnvironment(Method, Class)
*/
protected boolean isTestMethodIgnored(FrameworkMethod frameworkMethod) {
@ -295,7 +297,7 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Performs the same logic as
* Perform the same logic as
* {@link BlockJUnit4ClassRunner#possiblyExpectingExceptions(FrameworkMethod, Object, Statement)}
* except that the <em>expected exception</em> is retrieved using
* {@link #getExpectedException(FrameworkMethod)}.
@ -303,13 +305,14 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
@Override
protected Statement possiblyExpectingExceptions(FrameworkMethod frameworkMethod, Object testInstance, Statement next) {
Class<? extends Throwable> expectedException = getExpectedException(frameworkMethod);
return expectedException != null ? new ExpectException(next, expectedException) : next;
return (expectedException != null ? new ExpectException(next, expectedException) : next);
}
/**
* Get the {@code exception} that the supplied {@link FrameworkMethod
* Get the {@code exception} that the supplied {@linkplain FrameworkMethod
* test method} is expected to throw.
* <p>Supports JUnit's {@link Test#expected() @Test(expected=...)} annotation.
* <p>Can be overridden by subclasses.
* @return the expected exception, or {@code null} if none was specified
*/
protected Class<? extends Throwable> getExpectedException(FrameworkMethod frameworkMethod) {
@ -321,11 +324,14 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Supports both Spring's {@link Timed @Timed} and JUnit's
* Perform the same logic as
* {@link BlockJUnit4ClassRunner#withPotentialTimeout(FrameworkMethod, Object, Statement)}
* but with additional support for Spring's {@code @Timed} annotation.
* <p>Supports both Spring's {@link Timed @Timed} and JUnit's
* {@link Test#timeout() @Test(timeout=...)} annotations, but not both
* simultaneously. Returns either a {@link SpringFailOnTimeout}, a
* {@link FailOnTimeout}, or the unmodified, supplied {@link Statement} as
* appropriate.
* simultaneously.
* @return either a {@link SpringFailOnTimeout}, a {@link FailOnTimeout},
* or the supplied {@link Statement} as appropriate
* @see #getSpringTimeout(FrameworkMethod)
* @see #getJUnitTimeout(FrameworkMethod)
*/
@ -335,10 +341,11 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
long springTimeout = getSpringTimeout(frameworkMethod);
long junitTimeout = getJUnitTimeout(frameworkMethod);
if (springTimeout > 0 && junitTimeout > 0) {
String msg = "Test method [" + frameworkMethod.getMethod()
+ "] has been configured with Spring's @Timed(millis=" + springTimeout
+ ") and JUnit's @Test(timeout=" + junitTimeout
+ ") annotations. Only one declaration of a 'timeout' is permitted per test method.";
String msg = String.format(
"Test method [%s] has been configured with Spring's @Timed(millis=%s) and "
+ "JUnit's @Test(timeout=%s) annotations, but only one declaration of "
+ "a 'timeout' is permitted per test method.",
frameworkMethod.getMethod(), springTimeout, junitTimeout);
logger.error(msg);
throw new IllegalStateException(msg);
}
@ -356,9 +363,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Retrieves the configured JUnit {@code timeout} from the {@link Test @Test}
* annotation on the supplied {@link FrameworkMethod test method}.
* @return the timeout, or {@code 0} if none was specified.
* Retrieve the configured JUnit {@code timeout} from the {@link Test @Test}
* annotation on the supplied {@linkplain FrameworkMethod test method}.
* @return the timeout, or {@code 0} if none was specified
*/
protected long getJUnitTimeout(FrameworkMethod frameworkMethod) {
Test testAnnotation = frameworkMethod.getAnnotation(Test.class);
@ -366,10 +373,10 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Retrieves the configured Spring-specific {@code timeout} from the
* Retrieve the configured Spring-specific {@code timeout} from the
* {@link Timed @Timed} annotation on the supplied
* {@link FrameworkMethod test method}.
* @return the timeout, or {@code 0} if none was specified.
* {@linkplain FrameworkMethod test method}.
* @return the timeout, or {@code 0} if none was specified
*/
protected long getSpringTimeout(FrameworkMethod frameworkMethod) {
AnnotationAttributes annAttrs = AnnotatedElementUtils.getAnnotationAttributes(frameworkMethod.getMethod(),
@ -384,9 +391,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Wraps the {@link Statement} returned by the parent implementation with a
* Wrap the {@link Statement} returned by the parent implementation with a
* {@link RunBeforeTestMethodCallbacks} statement, thus preserving the
* default functionality but adding support for the Spring TestContext
* default functionality while adding support for the Spring TestContext
* Framework.
* @see RunBeforeTestMethodCallbacks
*/
@ -398,9 +405,9 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Wraps the {@link Statement} returned by the parent implementation with a
* Wrap the {@link Statement} returned by the parent implementation with a
* {@link RunAfterTestMethodCallbacks} statement, thus preserving the
* default functionality but adding support for the Spring TestContext
* default functionality while adding support for the Spring TestContext
* Framework.
* @see RunAfterTestMethodCallbacks
*/
@ -412,15 +419,20 @@ public class SpringJUnit4ClassRunner extends BlockJUnit4ClassRunner {
}
/**
* Supports Spring's {@link Repeat @Repeat} annotation by returning a
* 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 or {@code 1} if no repeat count is configured.
* count (if greater than {@code 1}); otherwise, the supplied statement
* is returned unmodified.
* @return either a {@link SpringRepeat} or the supplied {@link Statement}
* as appropriate
* @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 new SpringRepeat(next, frameworkMethod.getMethod(), repeat);
return (repeat > 1 ? new SpringRepeat(next, frameworkMethod.getMethod(), repeat) : next);
}
}

View File

@ -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.
@ -43,7 +43,7 @@ public class RunAfterTestClassCallbacks extends Statement {
/**
* Constructs a new {@code RunAfterTestClassCallbacks} statement.
* Construct a new {@code RunAfterTestClassCallbacks} statement.
*
* @param next the next {@code Statement} in the execution chain
* @param testContextManager the TestContextManager upon which to call
@ -55,11 +55,11 @@ public class RunAfterTestClassCallbacks extends Statement {
}
/**
* Invokes the next {@link Statement} in the execution chain (typically an instance of
* Evaluate the next {@link Statement} in the execution chain (typically an instance of
* {@link org.junit.internal.runners.statements.RunAfters RunAfters}), catching any
* exceptions thrown, and then calls {@link TestContextManager#afterTestClass()}. If
* the call to {@code afterTestClass()} throws an exception, it will also be tracked.
* Multiple exceptions will be combined into a {@link MultipleFailureException}.
* exceptions thrown, and then invoke {@link TestContextManager#afterTestClass()}.
* <p>If the invocation of {@code afterTestClass()} throws an exception, it will also
* be tracked. Multiple exceptions will be combined into a {@link MultipleFailureException}.
*/
@Override
public void evaluate() throws Throwable {

View File

@ -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.
@ -48,7 +48,7 @@ public class RunAfterTestMethodCallbacks extends Statement {
/**
* Constructs a new {@code RunAfterTestMethodCallbacks} statement.
* Construct a new {@code RunAfterTestMethodCallbacks} statement.
*
* @param next the next {@code Statement} in the execution chain
* @param testInstance the current test instance (never {@code null})
@ -66,12 +66,13 @@ public class RunAfterTestMethodCallbacks extends Statement {
}
/**
* Invokes the next {@link Statement} in the execution chain (typically an instance of
* Evaluate the next {@link Statement} in the execution chain (typically an instance of
* {@link org.junit.internal.runners.statements.RunAfters RunAfters}), catching any
* exceptions thrown, and then calls
* {@link TestContextManager#afterTestMethod(Object, Method, Throwable)} with the
* first caught exception (if any). If the call to {@code afterTestMethod()} throws an
* exception, it will also be tracked. Multiple exceptions will be combined into a
* exceptions thrown, and then invoke
* {@link TestContextManager#afterTestMethod(Object, Method, Throwable)} supplying the
* first caught exception (if any).
* <p>If the invocation of {@code afterTestMethod()} throws an exception, that
* exception will also be tracked. Multiple exceptions will be combined into a
* {@link MultipleFailureException}.
*/
@Override

View File

@ -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.
@ -39,7 +39,7 @@ public class RunBeforeTestClassCallbacks extends Statement {
/**
* Constructs a new {@code RunBeforeTestClassCallbacks} statement.
* Construct a new {@code RunBeforeTestClassCallbacks} statement.
*
* @param next the next {@code Statement} in the execution chain
* @param testContextManager the TestContextManager upon which to call
@ -51,9 +51,9 @@ public class RunBeforeTestClassCallbacks extends Statement {
}
/**
* Calls {@link TestContextManager#beforeTestClass()} and then invokes the next
* {@link Statement} in the execution chain (typically an instance of
* {@link org.junit.internal.runners.statements.RunBefores RunBefores}).
* Invoke {@link TestContextManager#beforeTestClass()} and then evaluate
* the next {@link Statement} in the execution chain (typically an instance
* of {@link org.junit.internal.runners.statements.RunBefores RunBefores}).
*/
@Override
public void evaluate() throws Throwable {

View File

@ -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.
@ -45,7 +45,7 @@ public class RunBeforeTestMethodCallbacks extends Statement {
/**
* Constructs a new {@code RunBeforeTestMethodCallbacks} statement.
* Construct a new {@code RunBeforeTestMethodCallbacks} statement.
*
* @param next the next {@code Statement} in the execution chain
* @param testInstance the current test instance (never {@code null})
@ -63,8 +63,9 @@ public class RunBeforeTestMethodCallbacks extends Statement {
}
/**
* Calls {@link TestContextManager#beforeTestMethod(Object, Method)} and then invokes
* the next {@link Statement} in the execution chain (typically an instance of
* Invoke {@link TestContextManager#beforeTestMethod(Object, Method)}
* and then evaluate the next {@link Statement} in the execution chain
* (typically an instance of
* {@link org.junit.internal.runners.statements.RunBefores RunBefores}).
*/
@Override

View File

@ -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.
@ -40,7 +40,7 @@ public class SpringFailOnTimeout extends Statement {
/**
* Constructs a new {@code SpringFailOnTimeout} statement.
* Construct a new {@code SpringFailOnTimeout} statement.
*
* @param next the next {@code Statement} in the execution chain
* @param timeout the configured {@code timeout} for the current test
@ -52,12 +52,12 @@ public class SpringFailOnTimeout extends Statement {
}
/**
* Invokes the next {@link Statement statement} in the execution chain
* 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 throws an exception if the next {@code statement}
* takes more than the specified {@code timeout}.
* ExpectException}) and throw a {@link TimeoutException} if the next
* {@code statement} executes longer than the specified {@code timeout}.
*/
@Override
public void evaluate() throws Throwable {

View File

@ -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.
@ -27,8 +27,8 @@ import org.springframework.util.ClassUtils;
/**
* {@code SpringRepeat} is a custom JUnit {@link Statement} which adds support
* for Spring's {@link Repeat @Repeat} annotation by repeating the test for
* the specified number of times.
* for Spring's {@link Repeat @Repeat} annotation by repeating the test the
* specified number of times.
*
* @see #evaluate()
* @author Sam Brannen
@ -46,7 +46,7 @@ public class SpringRepeat extends Statement {
/**
* Constructs a new {@code SpringRepeat} statement.
* Construct a new {@code SpringRepeat} statement.
*
* @param next the next {@code Statement} in the execution chain
* @param testMethod the current test method
@ -60,8 +60,8 @@ public class SpringRepeat extends Statement {
}
/**
* Invokes the next {@link Statement statement} in the execution chain for
* the specified repeat count.
* Evaluate the next {@link Statement statement} in the execution chain
* repeatedly, using the specified repeat count.
*/
@Override
public void evaluate() throws Throwable {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 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.
@ -41,11 +41,10 @@ import org.springframework.tests.sample.beans.Pet;
import static org.junit.Assert.*;
/**
* <p>
* SpringJUnit4ClassRunnerAppCtxTests serves as a <em>proof of concept</em>
* JUnit 4 based test class, which verifies the expected functionality of
* {@link SpringJUnit4ClassRunner} in conjunction with the following:
* </p>
*
* <ul>
* <li>{@link ContextConfiguration @ContextConfiguration}</li>
* <li>{@link Autowired @Autowired}</li>
@ -58,18 +57,15 @@ import static org.junit.Assert.*;
* <li>{@link BeanNameAware}</li>
* <li>{@link InitializingBean}</li>
* </ul>
* <p>
* Since no application context resource
*
* <p>Since no application context resource
* {@link ContextConfiguration#locations() locations} are explicitly declared
* and since the {@link ContextConfiguration#loader() ContextLoader} is left set
* to the default value of {@link GenericXmlContextLoader}, this test class's
* dependencies will be injected via {@link Autowired @Autowired},
* {@link Inject @Inject}, and {@link Resource @Resource} from beans defined in
* the {@link ApplicationContext} loaded from the default classpath resource:
*
* {@code &quot;/org/springframework/test/context/junit/SpringJUnit4ClassRunnerAppCtxTests-context.xml&quot;}
* .
* </p>
* {@value #DEFAULT_CONTEXT_RESOURCE_PATH}.
*
* @author Sam Brannen
* @since 2.5
@ -79,14 +75,12 @@ import static org.junit.Assert.*;
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class })
@TestExecutionListeners(DependencyInjectionTestExecutionListener.class)
public class SpringJUnit4ClassRunnerAppCtxTests implements ApplicationContextAware, BeanNameAware, InitializingBean {
/**
* Default resource path for the application context configuration for
* {@link SpringJUnit4ClassRunnerAppCtxTests}:
*
* {@code &quot;/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml&quot;}
* {@link SpringJUnit4ClassRunnerAppCtxTests}: {@value #DEFAULT_CONTEXT_RESOURCE_PATH}
*/
public static final String DEFAULT_CONTEXT_RESOURCE_PATH = "/org/springframework/test/context/junit4/SpringJUnit4ClassRunnerAppCtxTests-context.xml";