/** * From http://stackoverflow.com/questions/650894/change-test-name-of-parameterized-tests/2052202#2052202 * Licence: GPLv3 * Version: r3789 (Jan 2010) */ package uk.ac.lkl.common.util.testing; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.junit.runner.Description; import org.junit.runners.Parameterized; public class LabelledParameterized extends Parameterized { private List<String> labels; private Description labelledDescription; public LabelledParameterized(Class<?> cl) throws Throwable { super(cl); initialiseLabels(); generateLabelledDescription(); } private void initialiseLabels() throws Exception { Collection<Object[]> parameterArrays = getParameterArrays(); labels = new ArrayList<String>(); for (Object[] parameterArray : parameterArrays) { String label = parameterArray[0].toString(); labels.add(label); } } private Collection<Object[]> getParameterArrays() throws Exception { Method testClassMethod = getDeclaredMethod(this.getClass(), "getTestClass"); Class<?> returnType = testClassMethod.getReturnType(); if (returnType == Class.class) return getParameterArrays4_3(); else return getParameterArrays4_4(); } private Collection<Object[]> getParameterArrays4_3() throws Exception { Object[][] methodCalls = new Object[][] { new Object[] { "getTestClass" } }; Class<?> cl = invokeMethodChain(this, methodCalls); Method[] methods = cl.getMethods(); Method parametersMethod = null; for (Method method : methods) { boolean providesParameters = method .isAnnotationPresent(Parameters.class); if (!providesParameters) continue; if (parametersMethod != null) throw new Exception( "Only one method should be annotated with @Labels"); parametersMethod = method; } if (parametersMethod == null) throw new Exception("No @Parameters method found"); Collection<Object[]> parameterArrays = (Collection<Object[]>) parametersMethod .invoke(null); return parameterArrays; } private Collection<Object[]> getParameterArrays4_4() throws Exception { Object[][] methodCalls = new Object[][] { new Object[] { "getTestClass" }, new Object[] { "getAnnotatedMethods", Class.class, Parameters.class }, new Object[] { "get", int.class, 0 }, // use array type for varargs (equivalent (almost)) new Object[] { "invokeExplosively", Object.class, null, Object[].class, new Object[] {} } }; Collection<Object[]> parameterArrays = invokeMethodChain(this, methodCalls); return parameterArrays; } private <T> T invokeMethodChain(Object object, Object[][] methodCalls) throws Exception { for (Object[] methodCall : methodCalls) { String methodName = (String) methodCall[0]; int parameterCount = (methodCall.length - 1) / 2; Class<?>[] classes = new Class<?>[parameterCount]; Object[] arguments = new Object[parameterCount]; for (int i = 1; i < methodCall.length; i += 2) { Class<?> cl = (Class<?>) methodCall[i]; Object argument = methodCall[i + 1]; int index = (i - 1) / 2; // messy! classes[index] = cl; arguments[index] = argument; } Method method = getDeclaredMethod(object.getClass(), methodName, classes); object = method.invoke(object, arguments); } return (T) object; } // iterates through super-classes until found. Throws NoSuchMethodException // if not private Method getDeclaredMethod(Class<?> cl, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException { do { try { Method method = cl .getDeclaredMethod(methodName, parameterTypes); return method; } catch (NoSuchMethodException e) { // do nothing - just fall through to the below } cl = cl.getSuperclass(); } while (cl != null); throw new NoSuchMethodException("Method " + methodName + "() not found in hierarchy"); } private void generateLabelledDescription() throws Exception { Description originalDescription = super.getDescription(); labelledDescription = Description .createSuiteDescription(originalDescription.getDisplayName()); ArrayList<Description> childDescriptions = originalDescription .getChildren(); int childCount = childDescriptions.size(); if (childCount != labels.size()) throw new Exception( "Number of labels and number of parameters must match."); for (int i = 0; i < childDescriptions.size(); i++) { Description childDescription = childDescriptions.get(i); String label = labels.get(i); Description newDescription = Description .createSuiteDescription(label); ArrayList<Description> grandChildren = childDescription .getChildren(); for (Description grandChild : grandChildren) newDescription.addChild(grandChild); labelledDescription.addChild(newDescription); } } @Override public Description getDescription() { return labelledDescription; } }