All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.hiber.testcase.runners.inner.InnerTestCaseRunner Maven / Gradle / Ivy

There is a newer version: 0.12
Show 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.internal.runners.statements.RunAfters;
import org.junit.internal.runners.statements.RunBefores;
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.AfterTestCase;
import pl.hiber.testcase.annotations.BeforeTestCase;
import pl.hiber.testcase.annotations.TestCase;
import pl.hiber.testcase.annotations.TestObject;
import pl.hiber.testcase.statements.FrameworkMethodAction;
import pl.hiber.testcase.statements.ListAnswer;

import java.lang.reflect.Field;
import java.util.*;

/**
 * Created 2014 by 4ib3r
 * Runner for single test case.
 */
public class InnerTestCaseRunner extends ParentRunner {

    /** Test case method */
    protected FrameworkMethod frameworkMethod;

    /** List tests in single test case */
    protected List testsList;

    /** Test instance */
    protected Object testInstance;

    /** List of created instances used with test */
    protected Map testInstances;

    /** Constructor that's allow to create runner for simple test case */
	public InnerTestCaseRunner(Class testClass, FrameworkMethod frameworkMethod, Object testInstance, Map otherTestInstances)
            throws InitializationError {
		super(testClass);
		try {
			this.frameworkMethod = frameworkMethod;
            this.testInstance = testInstance;
            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() {
        TestCase testCase = frameworkMethod.getAnnotation(TestCase.class);
        if (testCase != null && !"".equals(testCase.value()))
            return testCase.value();
		return frameworkMethod.getName();
	}

    /** Describe test in test case */
	@Override
	protected Description describeChild(FrameworkMethodAction child) {
		if (child.isAction())
			return describeAction(child);
		return describeTest(child);
	}

	/** Create description for Test, use {@link #testName(pl.hiber.testcase.statements.FrameworkMethodAction)}
	 * for generate description */
	private Description describeTest(FrameworkMethodAction method) {
		return Description.createTestDescription(getName(), testName(method), calcMethodHashCode(method));
	}

	/** Create description for TestAction, use {@link #actionName(pl.hiber.testcase.statements.FrameworkMethodAction)}
	 * for generate description */
	private Description describeAction(FrameworkMethodAction method) {
		return Description.createTestDescription(getName(), actionName(method), calcMethodHashCode(method));
	}

    /** Calculate hash code for tests descriptions matching */
	private int calcMethodHashCode(FrameworkMethodAction method) {
		int result = 1;
		result = 31 * result + method.hashCode();
		result = 31 * result + frameworkMethod.hashCode();
		return result;
	}

	/** Generate name for TestAction */
	protected String actionName(FrameworkMethodAction frameworkMethod) {
		String action = "this";
        if (frameworkMethod.getTestInstance() == null) {
            action = "";
        } else if (frameworkMethod.getTestInstance().getClass() != getTestClass().getJavaClass())
			action = frameworkMethod.getTestInstance().getClass().getSimpleName();
        StringBuilder methodNameBuilder = new StringBuilder(frameworkMethod.getName());
        appendParameters(methodNameBuilder, frameworkMethod, true);
        if (frameworkMethod.getChainMethod() != null) { //Add submethods to name
            methodNameBuilder.append(actionName(frameworkMethod.getChainMethod()));
        }
		return String.format("%s.%s", action, methodNameBuilder.toString());
	}

    private void appendParameters(StringBuilder methodNameBuilder, FrameworkMethodAction frameworkMethod,
                                  boolean isAction) {
        if (isAction) {
            methodNameBuilder.append("(");
        }
        if(frameworkMethod.getParameters() != null && frameworkMethod.getParameters().length > 0) {
            if (!isAction) {
                methodNameBuilder.append(" [");
            }
            for (int i = 0; i < frameworkMethod.getParameters().length; i++) {
                Object o = frameworkMethod.getParameters()[i];
                if (i > 0) {
                    methodNameBuilder.append(", ");
                }
                if (o != null)
                    methodNameBuilder.append(o.toString());
                else
                    methodNameBuilder.append("null");
            }
            if (!isAction) {
                methodNameBuilder.append("]");
            }
        }
        if (isAction) {
            methodNameBuilder.append(")");
        }
    }

	/** Generate name for Test */
	protected String testName(FrameworkMethodAction frameworkMethod) {
        StringBuilder stringBuilder = new StringBuilder();
        if (frameworkMethod.getTestInstance().getClass() != getTestClass().getJavaClass())
            stringBuilder.append(frameworkMethod.getTestInstance().getClass().getSimpleName()).append(".");
        stringBuilder.append(frameworkMethod.getName());
        appendParameters(stringBuilder, frameworkMethod, false);
		return stringBuilder.toString();
	}


	/** 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
                child.invoke();
			} 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 = withBeforeTestCases(statement);
        statement = withAfterTestCases(statement);
        return statement;
    }

    /** Create statement for after test case methods {@link pl.hiber.testcase.annotations.AfterTestCase} */
    protected Statement withAfterTestCases(Statement statement) {
        List afters = getTestClass()
                .getAnnotatedMethods(AfterTestCase.class);
        return afters.isEmpty() ? statement :
                new RunAfters(statement, afters, testInstance);
    }

    /** Create statement for before test case methods {@link pl.hiber.testcase.annotations.BeforeTestCase} */
    protected Statement withBeforeTestCases(Statement statement) {
        List afters = getTestClass()
                .getAnnotatedMethods(BeforeTestCase.class);
        return afters.isEmpty() ? statement :
                new RunBefores(statement, afters, testInstance);
    }

	/** 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++) {
			Object bean = createOrGetTestInstance(parameterTypes[i]);
			mocks[i] = Mockito.mock(parameterTypes[i],
									new ListAnswer(subTestsList, bean, getTestClass().getJavaClass()));
		}
        //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();
        Field[] declaredFields = testInstance.getClass().getDeclaredFields();
        List fieldList = new ArrayList<>(fields.length + declaredFields.length);
        fieldList.addAll(Arrays.asList(fields));
        fieldList.addAll(Arrays.asList(declaredFields));
        for (Field field : fieldList) {
            TestObject testObject = field.getAnnotation(TestObject.class);
            if (testObject != null) {
                field.setAccessible(true);
                Object testObjectInstance = createOrGetTestInstance(field.getType());
                ListAnswer listAnswer = new ListAnswer(subTestsList, testObjectInstance,
                        getTestClass().getJavaClass());
                field.set(testInstance, testObjectInstance);
                field.set(testInstanceMock, Mockito.mock(field.getType(), listAnswer));
            }
        }

    }

    /** Creation new instance of test class or pojo, or get it from list if it exist. */
    protected Object createOrGetTestInstance(Class type) throws IllegalAccessException, InstantiationException {
        Object testInstance = testInstances.get(type.getName());
        if (testInstance == null) {
            testInstance = type.newInstance();
            testInstances.put(type.getName(), testInstance);
        }
        return testInstance;
    }

    public void buildActionsList() throws InitializationError {
        try {
            testsList = buildActionsList(frameworkMethod);
        } catch (Throwable throwable) {
            throw new InitializationError(throwable);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy