|
Spring Framework example source code file (SpringMethodRoadie.java)
The Spring Framework SpringMethodRoadie.java source code
/*
* Copyright 2002-2008 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;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Assume.AssumptionViolatedException;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.annotation.Timed;
import org.springframework.test.context.TestContextManager;
/**
* <p>
* <code>SpringMethodRoadie is a custom implementation of JUnit 4.4's
* {@link org.junit.internal.runners.MethodRoadie MethodRoadie}, which provides
* the following enhancements:
* </p>
* <ul>
* <li>Notifies a {@link TestContextManager} of
* {@link TestContextManager#beforeTestMethod(Object,Method) before} and
* {@link TestContextManager#afterTestMethod(Object,Method,Throwable) after}
* events.</li>
* <li>Uses a {@link SpringTestMethod} instead of JUnit 4.4's
* {@link org.junit.internal.runners.TestMethod TestMethod}.</li>
* <li>Tracks the exception thrown during execution of the test method.
* </ul>
* <p>
* Due to method and field visibility constraints, the code of
* <code>MethodRoadie has been duplicated here instead of subclassing
* <code>MethodRoadie directly.
* </p>
*
* @author Sam Brannen
* @author Juergen Hoeller
* @since 2.5
*/
class SpringMethodRoadie {
protected static final Log logger = LogFactory.getLog(SpringMethodRoadie.class);
private final TestContextManager testContextManager;
private final Object testInstance;
private final SpringTestMethod testMethod;
private final RunNotifier notifier;
private final Description description;
private Throwable testException;
/**
* Constructs a new <code>SpringMethodRoadie.
* @param testContextManager the TestContextManager to notify
* @param testInstance the test instance upon which to invoke the test method
* @param testMethod the test method to invoke
* @param notifier the RunNotifier to notify
* @param description the test description
*/
public SpringMethodRoadie(TestContextManager testContextManager, Object testInstance,
SpringTestMethod testMethod, RunNotifier notifier, Description description) {
this.testContextManager = testContextManager;
this.testInstance = testInstance;
this.testMethod = testMethod;
this.notifier = notifier;
this.description = description;
}
/**
* Runs the <em>test, including notification of events to the
* {@link RunNotifier} and {@link TestContextManager} as well as proper
* handling of {@link org.junit.Ignore @Ignore},
* {@link org.junit.Test#expected() expected exceptions},
* {@link org.junit.Test#timeout() test timeouts}, and
* {@link org.junit.Assume.AssumptionViolatedException assumptions}.
*/
public void run() {
if (this.testMethod.isIgnored()) {
this.notifier.fireTestIgnored(this.description);
return;
}
this.notifier.fireTestStarted(this.description);
try {
Timed timedAnnotation = this.testMethod.getMethod().getAnnotation(Timed.class);
long springTimeout = (timedAnnotation != null && timedAnnotation.millis() > 0 ?
timedAnnotation.millis() : 0);
long junitTimeout = this.testMethod.getTimeout();
if (springTimeout > 0 && junitTimeout > 0) {
throw new IllegalStateException("Test method [" + this.testMethod.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.");
}
else if (springTimeout > 0) {
long startTime = System.currentTimeMillis();
try {
runTest();
}
finally {
long elapsed = System.currentTimeMillis() - startTime;
if (elapsed > springTimeout) {
addFailure(new TimeoutException("Took " + elapsed + " ms; limit was " + springTimeout));
}
}
}
else if (junitTimeout > 0) {
runWithTimeout(junitTimeout);
}
else {
runTest();
}
}
finally {
this.notifier.fireTestFinished(this.description);
}
}
/**
* Runs the test method on the test instance with the specified
* <code>timeout.
* @param timeout the timeout in milliseconds
* @see #runWithRepetitions(Runnable)
* @see #runTestMethod()
*/
protected void runWithTimeout(final long timeout) throws CancellationException {
runWithRepetitions(new Runnable() {
public void run() {
ExecutorService service = Executors.newSingleThreadExecutor();
Future result = service.submit(new RunBeforesThenTestThenAfters());
service.shutdown();
try {
boolean terminated = service.awaitTermination(timeout, TimeUnit.MILLISECONDS);
if (!terminated) {
service.shutdownNow();
}
// Throws the exception if one occurred during the invocation.
result.get(0, TimeUnit.MILLISECONDS);
}
catch (TimeoutException ex) {
String message = "Test timed out after " + timeout + " milliseconds";
addFailure(new TimeoutException(message));
// We're cancelling repetitions here since we don't want
// the abandoned test method execution to conflict with
// further execution attempts of the same test method.
throw new CancellationException(message);
}
catch (ExecutionException ex) {
addFailure(ex.getCause());
}
catch (Exception ex) {
addFailure(ex);
}
}
});
}
/**
* Runs the test, including {@link #runBefores() @Before} and
* {@link #runAfters() @After} methods.
* @see #runWithRepetitions(Runnable)
* @see #runTestMethod()
*/
protected void runTest() {
runWithRepetitions(new RunBeforesThenTestThenAfters());
}
/**
* Runs the supplied <code>test with repetitions. Checks for the
* presence of {@link Repeat @Repeat} to determine if the test should be run
* more than once. The test will be run at least once.
* @param test the runnable test
* @see Repeat
*/
protected void runWithRepetitions(Runnable test) {
Method method = this.testMethod.getMethod();
Repeat repeat = method.getAnnotation(Repeat.class);
int runs = (repeat != null && repeat.value() > 1 ? repeat.value() : 1);
for (int i = 0; i < runs; i++) {
if (runs > 1 && logger.isInfoEnabled()) {
logger.info("Repetition " + (i + 1) + " of test " + method.getName());
}
try {
test.run();
}
catch (CancellationException ex) {
break;
}
}
}
/**
* Runs the test method on the test instance, processing exceptions
* (both expected and unexpected), assumptions, and registering
* failures as necessary.
*/
protected void runTestMethod() {
this.testException = null;
try {
this.testMethod.invoke(this.testInstance);
if (this.testMethod.expectsException()) {
addFailure(new AssertionError("Expected exception: " + this.testMethod.getExpectedException().getName()));
}
}
catch (InvocationTargetException ex) {
this.testException = ex.getTargetException();
if (!(this.testException instanceof AssumptionViolatedException)) {
if (!this.testMethod.expectsException()) {
addFailure(this.testException);
}
else if (this.testMethod.isUnexpected(this.testException)) {
addFailure(new Exception("Unexpected exception, expected <" +
this.testMethod.getExpectedException().getName() + "> but was <" +
this.testException.getClass().getName() + ">", this.testException));
}
}
}
catch (Throwable ex) {
addFailure(ex);
}
finally {
if (logger.isDebugEnabled()) {
logger.debug("Test method [" + this.testMethod.getMethod() + "] threw exception: " +
this.testException);
}
}
}
/**
* Calls {@link TestContextManager#beforeTestMethod} and then runs
* {@link org.junit.Before @Before methods}, registering failures
* and throwing {@link FailedBefore} exceptions as necessary.
* @throws FailedBefore if an error occurs while executing a <em>before method
*/
protected void runBefores() throws FailedBefore {
try {
this.testContextManager.beforeTestMethod(this.testInstance, this.testMethod.getMethod());
List<Method> befores = this.testMethod.getBefores();
for (Method before : befores) {
before.invoke(this.testInstance);
}
}
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
if (!(targetEx instanceof AssumptionViolatedException)) {
addFailure(targetEx);
}
throw new FailedBefore();
}
catch (Throwable ex) {
addFailure(ex);
throw new FailedBefore();
}
}
/**
* Runs {@link org.junit.After @After methods}, registering failures as
* necessary, and then calls {@link TestContextManager#afterTestMethod}.
*/
protected void runAfters() {
List<Method> afters = this.testMethod.getAfters();
for (Method after : afters) {
try {
after.invoke(this.testInstance);
}
catch (InvocationTargetException ex) {
addFailure(ex.getTargetException());
}
catch (Throwable ex) {
addFailure(ex);
}
}
try {
this.testContextManager.afterTestMethod(this.testInstance, this.testMethod.getMethod(), this.testException);
}
catch (Throwable ex) {
addFailure(ex);
}
}
/**
* Fire a failure for the supplied <code>exception with the
* {@link RunNotifier}.
* @param exception the exception upon which to base the failure
*/
protected void addFailure(Throwable exception) {
this.notifier.fireTestFailure(new Failure(this.description, exception));
}
/**
* Runs the test method, executing <code>@Before and
Other Spring Framework examples (source code examples)Here is a short list of links related to this Spring Framework SpringMethodRoadie.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.