package org.junit.runners; 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; import org.junit.runner.Runner; import org.junit.runner.notification.RunNotifier; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; import org.junit.runners.model.Statement; import org.junit.runners.model.TestClass; /** *

* The custom runner Parameterized implements parameterized tests. * When running a parameterized test class, instances are created for the * cross-product of the test methods and the test data elements. *

* * For example, to test a Fibonacci function, write: * *
 * @RunWith(Parameterized.class)
 * public class FibonacciTest {
 * 	@Parameters
 * 	public static List<Object[]> data() {
 * 		return Arrays.asList(new Object[][] {
 * 			{ 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
 * 		});
 * 	}
 * 
 * 	private int fInput;
 * 
 * 	private int fExpected;
 * 
 * 	public FibonacciTest(int input, int expected) {
 * 		fInput= input;
 * 		fExpected= expected;
 * 	}
 * 
 * 	@Test
 * 	public void test() {
 * 		assertEquals(fExpected, Fibonacci.compute(fInput));
 * 	}
 * }
 * 
* *

* Each instance of FibonacciTest will be constructed using the * two-argument constructor and the data values in the * @Parameters method. *

*/ public class Parameterized extends Suite { /** * Annotation for a method which provides parameters to be injected into the * test class constructor by Parameterized */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public static @interface Parameters { } private class TestClassRunnerForParameters extends BlockJUnit4ClassRunner { private final int fParameterSetNumber; private final List fParameterList; TestClassRunnerForParameters(Class type, List parameterList, int i) throws InitializationError { super(type); fParameterList= parameterList; fParameterSetNumber= i; } @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())); } } @Override protected String getName() { return String.format("[%s]", fParameterSetNumber); } @Override protected String testName(final FrameworkMethod method) { return String.format("%s[%s]", method.getName(), fParameterSetNumber); } @Override protected void validateConstructor(List errors) { validateOnlyOneConstructor(errors); } @Override protected Statement classBlock(RunNotifier notifier) { return childrenInvoker(notifier); } @Override protected Annotation[] getRunnerAnnotations() { return new Annotation[0]; } } private final ArrayList runners= new ArrayList(); /** * Only called reflectively. Do not use programmatically. */ public Parameterized(Class klass) throws Throwable { super(klass, Collections.emptyList()); List parametersList= getParametersList(getTestClass()); for (int i= 0; i < parametersList.size(); i++) runners.add(new TestClassRunnerForParameters(getTestClass().getJavaClass(), parametersList, i)); } @Override protected List getChildren() { return runners; } @SuppressWarnings("unchecked") private List getParametersList(TestClass klass) throws Throwable { return (List) getParametersMethod(klass).invokeExplosively( null); } private FrameworkMethod getParametersMethod(TestClass testClass) throws Exception { List 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()); } }