pl.hiber.testcase.runners.inner.InnerTestCaseRunner Maven / Gradle / Ivy
The newest version!
package pl.hiber.testcase.runners.inner;
import org.junit.Ignore;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.runners.model.EachTestNotifier;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.ParentRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.mockito.Mockito;
import pl.hiber.testcase.annotations.TestObject;
import pl.hiber.testcase.helpers.RulesFactory;
import pl.hiber.testcase.helpers.TestCaseNamingHelper;
import pl.hiber.testcase.helpers.TestObjectsFactory;
import pl.hiber.testcase.statements.FrameworkMethodAction;
import pl.hiber.testcase.statements.FrameworkMethodStatement;
import pl.hiber.testcase.answers.ListAnswer;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created 2014 by 4ib3r
* Runner for single test case.
*/
public class InnerTestCaseRunner extends ParentRunner {
/** Test case method */
protected FrameworkMethod frameworkMethod;
/** Test case param */
protected String param;
/** List tests in single test case */
protected List testsList;
/** Test instance */
protected Object testInstance;
/** List of created instances used with test */
protected Map testInstances;
/** Helper for names and descriptions used in runner */
private TestCaseNamingHelper testCaseNamingHelper;
/** Factory for before, after and rules statements */
private RulesFactory rulesFactory;
/** Constructor that's allow to create runner for simple test case */
public InnerTestCaseRunner(Class> testClass, FrameworkMethod frameworkMethod, Object testInstance,
Map otherTestInstances, String param)
throws InitializationError {
super(testClass);
try {
this.param = param;
this.frameworkMethod = frameworkMethod;
this.testInstance = testInstance;
this.testCaseNamingHelper = new TestCaseNamingHelper(testClass, frameworkMethod, param);
this.rulesFactory = new RulesFactory(testInstance, getTestClass());
this.testInstances = otherTestInstances;
if (this.testInstances == null) {
this.testInstances = new HashMap<>(1, 1);
}
this.testInstances.put(testInstance.getClass().getName(), testInstance);
} catch (Throwable e) {
throw new InitializationError(e);
}
}
/** Return all tests method's in test case */
@Override
protected List getChildren() {
return testsList;
}
/** Provide name for test case */
@Override
protected String getName() {
return testCaseNamingHelper.getName();
}
/** Describe test in test case */
@Override
protected Description describeChild(FrameworkMethodAction child) {
return testCaseNamingHelper.describeChild(child);
}
/** Generate description TestCase element and run it.
* Before run check {@link org.junit.Ignore} annotation */
@Override
protected void runChild(FrameworkMethodAction child, RunNotifier notifier) {
EachTestNotifier eachNotifier = new EachTestNotifier(notifier, describeChild(child));
eachNotifier.fireTestStarted();
if (child.getAnnotation(Ignore.class) != null) {
eachNotifier.fireTestIgnored();
} else {
try { //Invoke child with sub childs
Statement statement = new FrameworkMethodStatement(child);
statement = rulesFactory.withRules(child, testInstance, statement, describeChild(child));
statement.evaluate();
} catch (AssumptionViolatedException e) {
eachNotifier.addFailedAssumption(e);
} catch (Throwable e) {
eachNotifier.addFailure(e);
}
}
eachNotifier.fireTestFinished();
}
/** Build test case run block, run tests and before/after test case methods */
@Override
protected Statement classBlock(final RunNotifier notifier) {
Statement statement = childrenInvoker(notifier);
statement = rulesFactory.withBeforeTestCases(statement);
statement = rulesFactory.withAfterTestCases(statement);
statement = rulesFactory.withTestCasesRules(statement, testInstance, getDescription());
return statement;
}
/** Build tests and actions list for test case */
private List buildActionsList(FrameworkMethod fm) throws Throwable {
List subTestsList = new ArrayList();
Class>[] parameterTypes = fm.getMethod().getParameterTypes();
Object[] mocks = new Object[parameterTypes.length];
//Set mock's for all test case method parameters
for(int i = 0; i < parameterTypes.length; i++) {
if (!parameterTypes[i].isPrimitive() &&
!Number.class.isAssignableFrom(parameterTypes[i]) &&
parameterTypes[i] != String.class) {
Object bean = TestObjectsFactory.createOrGetTestInstance(parameterTypes[i], testInstances);
mocks[i] = Mockito.mock(parameterTypes[i],
new ListAnswer(subTestsList, bean, getTestClass().getJavaClass()));
} else if (param != null) {
if (String.class.equals(parameterTypes[i])) {
mocks[i] = param;
} else if (Integer.class.isAssignableFrom(parameterTypes[i])) {
mocks[i] = Integer.parseInt(param);
} else if (parameterTypes[i].isAssignableFrom(Long.class)) {
mocks[i] = Long.parseLong(param);
} else if (parameterTypes[i].isAssignableFrom(Float.class)) {
mocks[i] = Float.parseFloat(param);
} else if (parameterTypes[i].isAssignableFrom(Double.class)) {
mocks[i] = Double.parseDouble(param);
} else if (parameterTypes[i].isAssignableFrom(BigDecimal.class)) {
mocks[i] = new BigDecimal(param);
} else {
throw new UnsupportedOperationException("Parameter has not supported type");
}
}
}
//Create mock of test instance for collect methods invoked on "this" in test case
ListAnswer listAnswer = new ListAnswer(subTestsList, testInstance);
Object testInstanceMock = Mockito.mock(getTestClass().getJavaClass(), listAnswer);
mockTestObjects(testInstance, testInstanceMock, subTestsList);
//Invoke test case method, build tests flow defined in method.
fm.invokeExplosively(testInstanceMock, mocks);
return subTestsList;
}
private void mockTestObjects(Object testInstance, Object testInstanceMock,
List subTestsList)
throws IllegalAccessException, InstantiationException {
Field[] fields = testInstance.getClass().getFields();
for (Field field : fields) {
Object testObjectInstance = createTestObjectInstance(field);
if (testObjectInstance == null) {
continue;
}
ListAnswer listAnswer = new ListAnswer(subTestsList, testObjectInstance,
getTestClass().getJavaClass());
field.set(testInstance, testObjectInstance);
field.set(testInstanceMock, Mockito.mock(field.getType(), listAnswer));
}
}
protected Object createTestObjectInstance(Field field)
throws InstantiationException, IllegalAccessException {
TestObject testObject = field.getAnnotation(TestObject.class);
if (testObject != null) {
Object testObjectInstance = field.get(testInstance);
if (testObjectInstance == null && testObject.autoCreate()) {
testObjectInstance = TestObjectsFactory.createOrGetTestInstance(field.getType(), testInstances);
}
return testObjectInstance;
}
return null;
}
/** Build tests list for test case, prepare test case in {@link pl.hiber.testcase.runners.TestCaseRunner} */
public void buildActionsList() throws InitializationError {
try {
testsList = buildActionsList(frameworkMethod);
} catch (Throwable throwable) {
throw new InitializationError(throwable);
}
}
}