package test_util; import test_util.StringUtils; import org.junit.runner.Runner; import org.junit.runner.notification.RunNotifier; import org.junit.runners.BlockJUnit4ClassRunner; import org.junit.runners.Suite; 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.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.List; // Modified version of // https://github.com/dynacron-group/parallel-webtest/blob/master/src/main/java/com/dynacrongroup/webtest/DescriptivelyParameterized.java /** * This is modification of org.junit.runners.Parameterized to descriptively * parameterize tests. The purpose of this modification is to use parameters in * the test names instead of set number, so that failures can be traced back to * the parameters used. * <p/> * Note that this class must be used with String parameters; it's not intended * for general use, only for use with ParallelRunner and WebDriverBase. * * To back out the inclusion of this class, you'll need to change the extension * for ParallelRunner back to "Parameterized" and change the annotation in * WebDriverBase back to "Parameterized". */ @SuppressWarnings("all") public class DescriptivelyParameterized extends Suite { /** * Annotation for a method which provides parameters to be injected into the * test class constructor by <code>DescriptivelyParameterized</code> */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public static @interface Parameters { } private class TestClassRunnerForParameters extends BlockJUnit4ClassRunner { private final int fParameterSetNumber; private final List<Object[]> fParameterList; private final String fParameterDescription; TestClassRunnerForParameters(Class<?> type, List<Object[]> parameterList, int i) throws InitializationError { super(type); fParameterList = parameterList; fParameterSetNumber = i; fParameterDescription = describeParams(); } @Override public Object createTest() throws Exception { return getTestClass().getOnlyConstructor().newInstance( computeParams()); } private Object[] computeParams() throws Exception { try { return fParameterList.get(fParameterSetNumber); } catch (ClassCastException e) { throw new Exception(String.format( "%s.%s() must return a Collection of arrays.", getTestClass().getName(), getParametersMethod(getTestClass()).getName())); } } /* * Try to describe the parameters by converting to String; if this * fails, fall back to describing using fParameterSetNumber */ private String describeParams() { String returnValue; try { Object[] params = computeParams(); returnValue = formatParams(params); } catch (Exception e) { returnValue = null; } if (returnValue == null) { returnValue = ((Integer) fParameterSetNumber).toString(); } return returnValue; } /** * Override this method to provide custom parameter formatting. * * @param params * @return A formatted string to be appended to the test name. */ public String formatParams(Object[] params) { String formattedParams; String[] stringParams = (String[]) params; if (stringParams[1].contains("Driver")) { String driver = stringParams[1]; formattedParams = driver.substring(driver.lastIndexOf(".") + 1, driver.lastIndexOf("Driver")); } else { // Use undersocre instead of pipe. formattedParams = StringUtils.join(stringParams, "_"); } return formattedParams; } @Override protected String getName() { return String.format("[%s]", fParameterDescription); } @Override protected String testName(final FrameworkMethod method) { return String.format("%s[%s]", method.getName(), fParameterDescription); } @Override protected void validateConstructor(List<Throwable> errors) { validateOnlyOneConstructor(errors); } @Override protected Statement classBlock(RunNotifier notifier) { return childrenInvoker(notifier); } // @Override // protected Annotation[] getRunnerAnnotations() { // return new Annotation[0]; // } } private final ArrayList<Runner> runners = new ArrayList<Runner>(); /** * Only called reflectively. Do not use programmatically. */ public DescriptivelyParameterized(Class<?> klass) throws Throwable { super(klass, Collections.<Runner> emptyList()); List<Object[]> parametersList = getParametersList(getTestClass()); for (int i = 0; i < parametersList.size(); i++) runners.add(new TestClassRunnerForParameters(getTestClass() .getJavaClass(), parametersList, i)); } @Override protected List<Runner> getChildren() { return runners; } @SuppressWarnings("unchecked") private List<Object[]> getParametersList(TestClass klass) throws Throwable { return (List<Object[]>) getParametersMethod(klass).invokeExplosively( null); } private FrameworkMethod getParametersMethod(TestClass testClass) throws Exception { List<FrameworkMethod> methods = testClass .getAnnotatedMethods(Parameters.class); for (FrameworkMethod each : methods) { int modifiers = each.getMethod().getModifiers(); if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)) return each; } throw new Exception("No public static parameters method on class " + testClass.getName()); } }