org.junit.experimental.max.MaxCore Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of junit Show documentation
Show all versions of junit Show documentation
JUnit is a regression testing framework written by Erich Gamma and Kent Beck.
It is used by the developer who implements unit tests in Java.
package org.junit.experimental.max;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import junit.framework.TestSuite;
import org.junit.internal.requests.SortingRequest;
import org.junit.internal.runners.ErrorReportingRunner;
import org.junit.internal.runners.JUnit38ClassRunner;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;
import org.junit.runner.Runner;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;
/**
* A replacement for JUnitCore, which keeps track of runtime and failure history, and reorders tests
* to maximize the chances that a failing test occurs early in the test run.
*
* The rules for sorting are:
*
* - Never-run tests first, in arbitrary order
*
- Group remaining tests by the date at which they most recently failed.
*
- Sort groups such that the most recent failure date is first, and never-failing tests are at the end.
*
- Within a group, run the fastest tests first.
*
*/
public class MaxCore {
private static final String MALFORMED_JUNIT_3_TEST_CLASS_PREFIX = "malformed JUnit 3 test class: ";
/**
* Create a new MaxCore from a serialized file stored at storedResults
*
* @deprecated use storedLocally()
*/
@Deprecated
public static MaxCore forFolder(String folderName) {
return storedLocally(new File(folderName));
}
/**
* Create a new MaxCore from a serialized file stored at storedResults
*/
public static MaxCore storedLocally(File storedResults) {
return new MaxCore(storedResults);
}
private final MaxHistory fHistory;
private MaxCore(File storedResults) {
fHistory = MaxHistory.forFolder(storedResults);
}
/**
* Run all the tests in class
.
*
* @return a {@link Result} describing the details of the test run and the failed tests.
*/
public Result run(Class testClass) {
return run(Request.aClass(testClass));
}
/**
* Run all the tests contained in request
.
*
* @param request the request describing tests
* @return a {@link Result} describing the details of the test run and the failed tests.
*/
public Result run(Request request) {
return run(request, new JUnitCore());
}
/**
* Run all the tests contained in request
.
*
* This variant should be used if {@code core} has attached listeners that this
* run should notify.
*
* @param request the request describing tests
* @param core a JUnitCore to delegate to.
* @return a {@link Result} describing the details of the test run and the failed tests.
*/
public Result run(Request request, JUnitCore core) {
core.addListener(fHistory.listener());
return core.run(sortRequest(request).getRunner());
}
/**
* @return a new Request, which contains all of the same tests, but in a new order.
*/
public Request sortRequest(Request request) {
if (request instanceof SortingRequest) {
// We'll pay big karma points for this
return request;
}
List leaves = findLeaves(request);
Collections.sort(leaves, fHistory.testComparator());
return constructLeafRequest(leaves);
}
private Request constructLeafRequest(List leaves) {
final List runners = new ArrayList();
for (Description each : leaves) {
runners.add(buildRunner(each));
}
return new Request() {
@Override
public Runner getRunner() {
try {
return new Suite((Class) null, runners) {
};
} catch (InitializationError e) {
return new ErrorReportingRunner(null, e);
}
}
};
}
private Runner buildRunner(Description each) {
if (each.toString().equals("TestSuite with 0 tests")) {
return Suite.emptySuite();
}
if (each.toString().startsWith(MALFORMED_JUNIT_3_TEST_CLASS_PREFIX)) {
// This is cheating, because it runs the whole class
// to get the warning for this method, but we can't do better,
// because JUnit 3.8's
// thrown away which method the warning is for.
return new JUnit38ClassRunner(new TestSuite(getMalformedTestClass(each)));
}
Class type = each.getTestClass();
if (type == null) {
throw new RuntimeException("Can't build a runner from description [" + each + "]");
}
String methodName = each.getMethodName();
if (methodName == null) {
return Request.aClass(type).getRunner();
}
return Request.method(type, methodName).getRunner();
}
private Class getMalformedTestClass(Description each) {
try {
return Class.forName(each.toString().replace(MALFORMED_JUNIT_3_TEST_CLASS_PREFIX, ""));
} catch (ClassNotFoundException e) {
return null;
}
}
/**
* @param request a request to run
* @return a list of method-level tests to run, sorted in the order
* specified in the class comment.
*/
public List sortedLeavesForTest(Request request) {
return findLeaves(sortRequest(request));
}
private List findLeaves(Request request) {
List results = new ArrayList();
findLeaves(null, request.getRunner().getDescription(), results);
return results;
}
private void findLeaves(Description parent, Description description, List results) {
if (description.getChildren().isEmpty()) {
if (description.toString().equals("warning(junit.framework.TestSuite$1)")) {
results.add(Description.createSuiteDescription(MALFORMED_JUNIT_3_TEST_CLASS_PREFIX + parent));
} else {
results.add(description);
}
} else {
for (Description each : description.getChildren()) {
findLeaves(description, each, results);
}
}
}
}