com.github.dakusui.jcunit.runners.standard.JCUnitRunner Maven / Gradle / Ivy
package com.github.dakusui.jcunit.runners.standard;
import com.github.dakusui.jcunit.core.Checks;
import com.github.dakusui.jcunit.core.Utils;
import com.github.dakusui.jcunit.core.factor.FactorSpace;
import com.github.dakusui.jcunit.core.factor.Factors;
import com.github.dakusui.jcunit.core.tuples.TupleUtils;
import com.github.dakusui.jcunit.plugins.constraints.ConstraintChecker;
import com.github.dakusui.jcunit.runners.core.TestCase;
import com.github.dakusui.jcunit.runners.core.TestSuite;
import com.github.dakusui.jcunit.runners.standard.annotations.When;
import org.junit.Ignore;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;
import java.lang.annotation.Annotation;
import java.util.*;
/**
* Runs each test case.
*/
public class JCUnitRunner extends BlockJUnit4ClassRunner {
private final Factors factors;
private final TestSuite testSuite;
private final TestCase testCase;
private final Map methods;
private final ConstraintChecker constraintChecker;
private final FactorSpace factorSpace;
/**
* Creates an object of this class.
*
* @param clazz A test class.
* @param testCase A test case object. @throws InitializationError In case initialization is failed. e.g. More than one constructor is found in the test class.
*/
public JCUnitRunner(Class> clazz, FactorSpace factorSpace, ConstraintChecker constraintChecker, TestSuite testSuite, TestCase testCase) throws InitializationError {
super(clazz);
this.factorSpace = Checks.checknotnull(factorSpace);
this.factors = factorSpace.factors;
this.constraintChecker = Checks.checknotnull(constraintChecker);
this.testSuite = Checks.checknotnull(testSuite);
this.testCase = Checks.checknotnull(testCase);
TestClass testClass = getTestClass();
Map methods = new LinkedHashMap();
for (FrameworkMethod each : testClass.getAnnotatedMethods(When.class)) {
When when = each.getAnnotation(When.class);
CompositeFrameworkMethod compositeFrameworkMethod = FrameworkMethodUtils.buildCompositeFrameworkMethod(testClass, when);
methods.put(compositeFrameworkMethod.getName(), compositeFrameworkMethod);
}
this.methods = Collections.unmodifiableMap(methods);
}
/**
* Without overriding this method, all the tests will fail for 'AssertionError',
* because {@code {@literal @}BeforeClass} methods and {@code {@literal @}AfterClass}
* methods are executed for every test case run not before and after all the
* test cases are executed.
*
* {@code BlockJUnit4ClassRunnerWithParameters} does the same.
*
* @see org.junit.runners.BlockJUnit4ClassRunner#classBlock(org.junit.runner.notification.RunNotifier)
*/
@Override
protected Statement classBlock(RunNotifier notifier) {
return childrenInvoker(notifier);
}
/**
* Overrides super class's {@code createTestObject()} method, which throws a {@code java.lang.Exception},
* to simplify exception handling.
*/
@Override
public Object createTest() {
return TestCaseUtils.toTestObject(getTestClass().getJavaClass(), this.factorSpace.convert(testCase.getTuple()));
}
@Override
protected String getName() {
return String.format("[%d]", this.testCase.getId());
}
@Override
protected String testName(final FrameworkMethod method) {
return String.format("%s[%d]", method.getName(), this.testCase.getId());
}
@Override
protected void validateConstructor(List errors) {
validateZeroArgConstructor(errors);
}
@Override
protected Description describeChild(FrameworkMethod method) {
Checks.checknotnull(method);
String name = testName(method);
List super Annotation> annotations = Utils.newList(new InternalAnnotation(this.factors, this.constraintChecker, this.testSuite, this.testCase));
annotations.addAll(Utils.asList(method.getAnnotations()));
////
// Elements in the list are all annotations.
//noinspection SuspiciousToArrayCall
return Description.createTestDescription(
getTestClass().getJavaClass(),
name,
annotations.toArray(new Annotation[annotations.size()]));
}
@Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
Description description = describeChild(method);
if (method.getAnnotation(Ignore.class) != null) {
notifier.fireTestIgnored(description);
} else {
runLeaf(methodBlock(method), description, notifier);
}
}
@Override
protected List getChildren() {
List ret = new LinkedList();
for (FrameworkMethod each : computeTestMethods()) {
if (shouldInvoke(each, createTest()))
ret.add(each);
}
if (ret.isEmpty())
ret.add(getDummyMethodForNoMatchingMethodFound());
return ret;
}
private boolean shouldInvoke(FrameworkMethod testMethod, Object testObject) {
When when = testMethod.getAnnotation(When.class);
if (when == null)
return true;
// TODO Issue-#49
String preconditionMethodName = FrameworkMethodUtils.composePreconditionCompositeFrameworkMethodName(when);
FrameworkMethod preconditionMethod = this.methods.get(preconditionMethodName);
Checks.checkcond(preconditionMethod != null, "Something went wrong: name=%s, methdos=%s", preconditionMethodName, this.methods);
boolean ret;
try {
////
// It's guaranteed that preconditionMethod returns a boolean by validation process.
ret = (Boolean) preconditionMethod.invokeExplosively(testObject);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Throwable throwable) {
throw Checks.wrap(throwable);
}
return ret;
}
private FrameworkMethod getDummyMethodForNoMatchingMethodFound() {
try {
return new FrameworkMethod(JCUnitRunner.class.getMethod("noMatchingTestMethodIsFoundForThisTestCase")) {
@Override
public String getName() {
return String.format("%s:%s", super.getName(), TupleUtils.toString(JCUnitRunner.this.testCase.getTuple()));
}
};
} catch (NoSuchMethodException e) {
throw Checks.wrap(e);
}
}
/**
* This method is only used through reflection to let JUnit know the test case is ignored since
* no matching test method is defined for it.
*
* @see JCUnitRunner#getDummyMethodForNoMatchingMethodFound()
*/
@Ignore
@SuppressWarnings("unused")
public static void noMatchingTestMethodIsFoundForThisTestCase() {
}
} © 2015 - 2025 Weber Informatics LLC | Privacy Policy