aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/junit/runners/Parameterized.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/junit/runners/Parameterized.java')
-rw-r--r--src/main/java/org/junit/runners/Parameterized.java405
1 files changed, 126 insertions, 279 deletions
diff --git a/src/main/java/org/junit/runners/Parameterized.java b/src/main/java/org/junit/runners/Parameterized.java
index d11b66a..829c8f0 100644
--- a/src/main/java/org/junit/runners/Parameterized.java
+++ b/src/main/java/org/junit/runners/Parameterized.java
@@ -1,6 +1,5 @@
package org.junit.runners;
-import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
@@ -9,18 +8,12 @@ import java.lang.annotation.Target;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import org.junit.internal.AssumptionViolatedException;
-import org.junit.runner.Description;
-import org.junit.runner.Result;
import org.junit.runner.Runner;
-import org.junit.runner.notification.Failure;
-import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.InvalidTestClassError;
+import org.junit.runners.model.InitializationError;
import org.junit.runners.model.TestClass;
import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParametersFactory;
import org.junit.runners.parameterized.ParametersRunnerFactory;
@@ -31,37 +24,34 @@ import org.junit.runners.parameterized.TestWithParameters;
* When running a parameterized test class, instances are created for the
* cross-product of the test methods and the test data elements.
* <p>
- * For example, to test the <code>+</code> operator, write:
+ * For example, to test a Fibonacci function, write:
* <pre>
* &#064;RunWith(Parameterized.class)
- * public class AdditionTest {
- * &#064;Parameters(name = &quot;{index}: {0} + {1} = {2}&quot;)
+ * public class FibonacciTest {
+ * &#064;Parameters(name= &quot;{index}: fib[{0}]={1}&quot;)
* public static Iterable&lt;Object[]&gt; data() {
- * return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 },
- * { 3, 2, 5 }, { 4, 3, 7 } });
+ * return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
+ * { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
* }
*
- * private int firstSummand;
+ * private int fInput;
*
- * private int secondSummand;
+ * private int fExpected;
*
- * private int sum;
- *
- * public AdditionTest(int firstSummand, int secondSummand, int sum) {
- * this.firstSummand = firstSummand;
- * this.secondSummand = secondSummand;
- * this.sum = sum;
+ * public FibonacciTest(int input, int expected) {
+ * fInput= input;
+ * fExpected= expected;
* }
*
* &#064;Test
* public void test() {
- * assertEquals(sum, firstSummand + secondSummand);
+ * assertEquals(fExpected, Fibonacci.compute(fInput));
* }
* }
* </pre>
* <p>
- * Each instance of <code>AdditionTest</code> will be constructed using the
- * three-argument constructor and the data values in the
+ * Each instance of <code>FibonacciTest</code> will be constructed using the
+ * two-argument constructor and the data values in the
* <code>&#064;Parameters</code> method.
* <p>
* In order that you can easily identify the individual tests, you may provide a
@@ -79,36 +69,33 @@ import org.junit.runners.parameterized.TestWithParameters;
* </dl>
* <p>
* In the example given above, the <code>Parameterized</code> runner creates
- * names like <code>[2: 3 + 2 = 5]</code>. If you don't use the name parameter,
+ * names like <code>[1: fib(3)=2]</code>. If you don't use the name parameter,
* then the current parameter index is used as name.
* <p>
* You can also write:
* <pre>
* &#064;RunWith(Parameterized.class)
- * public class AdditionTest {
- * &#064;Parameters(name = &quot;{index}: {0} + {1} = {2}&quot;)
- * public static Iterable&lt;Object[]&gt; data() {
- * return Arrays.asList(new Object[][] { { 0, 0, 0 }, { 1, 1, 2 },
- * { 3, 2, 5 }, { 4, 3, 7 } });
- * }
- *
- * &#064;Parameter(0)
- * public int firstSummand;
+ * public class FibonacciTest {
+ * &#064;Parameters
+ * public static Iterable&lt;Object[]&gt; data() {
+ * return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
+ * { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
+ * }
+ *
+ * &#064;Parameter(0)
+ * public int fInput;
*
- * &#064;Parameter(1)
- * public int secondSummand;
+ * &#064;Parameter(1)
+ * public int fExpected;
*
- * &#064;Parameter(2)
- * public int sum;
- *
- * &#064;Test
- * public void test() {
- * assertEquals(sum, firstSummand + secondSummand);
- * }
+ * &#064;Test
+ * public void test() {
+ * assertEquals(fExpected, Fibonacci.compute(fInput));
+ * }
* }
* </pre>
* <p>
- * Each instance of <code>AdditionTest</code> will be constructed with the default constructor
+ * Each instance of <code>FibonacciTest</code> will be constructed with the default constructor
* and fields annotated by <code>&#064;Parameter</code> will be initialized
* with the data values in the <code>&#064;Parameters</code> method.
*
@@ -118,7 +105,8 @@ import org.junit.runners.parameterized.TestWithParameters;
* <pre>
* &#064;Parameters
* public static Object[][] data() {
- * return new Object[][] { { 0, 0, 0 }, { 1, 1, 2 }, { 3, 2, 5 }, { 4, 3, 7 } } };
+ * return new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 },
+ * { 5, 5 }, { 6, 8 } };
* }
* </pre>
*
@@ -142,19 +130,6 @@ import org.junit.runners.parameterized.TestWithParameters;
* }
* </pre>
*
- * <h3>Executing code before/after executing tests for specific parameters</h3>
- * <p>
- * If your test needs to perform some preparation or cleanup based on the
- * parameters, this can be done by adding public static methods annotated with
- * {@code @BeforeParam}/{@code @AfterParam}. Such methods should either have no
- * parameters or the same parameters as the test.
- * <pre>
- * &#064;BeforeParam
- * public static void beforeTestsForParameter(String onlyParameter) {
- * System.out.println("Testing " + onlyParameter);
- * }
- * </pre>
- *
* <h3>Create different runners</h3>
* <p>
* By default the {@code Parameterized} runner creates a slightly modified
@@ -166,7 +141,7 @@ import org.junit.runners.parameterized.TestWithParameters;
* The factory must have a public zero-arg constructor.
*
* <pre>
- * public class YourRunnerFactory implements ParametersRunnerFactory {
+ * public class YourRunnerFactory implements ParameterizedRunnerFactory {
* public Runner createRunnerForTestWithParameters(TestWithParameters test)
* throws InitializationError {
* return YourRunner(test);
@@ -185,21 +160,6 @@ import org.junit.runners.parameterized.TestWithParameters;
* }
* </pre>
*
- * <h3>Avoid creating parameters</h3>
- * <p>With {@link org.junit.Assume assumptions} you can dynamically skip tests.
- * Assumptions are also supported by the <code>&#064;Parameters</code> method.
- * Creating parameters is stopped when the assumption fails and none of the
- * tests in the test class is executed. JUnit reports a
- * {@link Result#getAssumptionFailureCount() single assumption failure} for the
- * whole test class in this case.
- * <pre>
- * &#064;Parameters
- * public static Iterable&lt;? extends Object&gt; data() {
- * String os = System.getProperty("os.name").toLowerCase()
- * Assume.assumeTrue(os.contains("win"));
- * return Arrays.asList(&quot;first test&quot;, &quot;second test&quot;);
- * }
- * </pre>
* @since 4.0
*/
public class Parameterized extends Suite {
@@ -210,7 +170,7 @@ public class Parameterized extends Suite {
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
- public @interface Parameters {
+ public static @interface Parameters {
/**
* Optional pattern to derive the test's name from the parameters. Use
* numbers in braces to refer to the parameters or the additional data
@@ -241,7 +201,7 @@ public class Parameterized extends Suite {
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
- public @interface Parameter {
+ public static @interface Parameter {
/**
* Method that returns the index of the parameter in the array
* returned by the method annotated by <code>Parameters</code>.
@@ -270,235 +230,122 @@ public class Parameterized extends Suite {
Class<? extends ParametersRunnerFactory> value() default BlockJUnit4ClassRunnerWithParametersFactory.class;
}
- /**
- * Annotation for {@code public static void} methods which should be executed before
- * evaluating tests with particular parameters.
- *
- * @see org.junit.BeforeClass
- * @see org.junit.Before
- * @since 4.13
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public @interface BeforeParam {
- }
+ private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory();
- /**
- * Annotation for {@code public static void} methods which should be executed after
- * evaluating tests with particular parameters.
- *
- * @see org.junit.AfterClass
- * @see org.junit.After
- * @since 4.13
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public @interface AfterParam {
- }
+ private static final List<Runner> NO_RUNNERS = Collections.<Runner>emptyList();
+
+ private final List<Runner> runners;
/**
* Only called reflectively. Do not use programmatically.
*/
public Parameterized(Class<?> klass) throws Throwable {
- this(klass, new RunnersFactory(klass));
- }
-
- private Parameterized(Class<?> klass, RunnersFactory runnersFactory) throws Exception {
- super(klass, runnersFactory.createRunners());
- validateBeforeParamAndAfterParamMethods(runnersFactory.parameterCount);
+ super(klass, NO_RUNNERS);
+ ParametersRunnerFactory runnerFactory = getParametersRunnerFactory(
+ klass);
+ Parameters parameters = getParametersMethod().getAnnotation(
+ Parameters.class);
+ runners = Collections.unmodifiableList(createRunnersForParameters(
+ allParameters(), parameters.name(), runnerFactory));
}
- private void validateBeforeParamAndAfterParamMethods(Integer parameterCount)
- throws InvalidTestClassError {
- List<Throwable> errors = new ArrayList<Throwable>();
- validatePublicStaticVoidMethods(Parameterized.BeforeParam.class, parameterCount, errors);
- validatePublicStaticVoidMethods(Parameterized.AfterParam.class, parameterCount, errors);
- if (!errors.isEmpty()) {
- throw new InvalidTestClassError(getTestClass().getJavaClass(), errors);
+ private ParametersRunnerFactory getParametersRunnerFactory(Class<?> klass)
+ throws InstantiationException, IllegalAccessException {
+ UseParametersRunnerFactory annotation = klass
+ .getAnnotation(UseParametersRunnerFactory.class);
+ if (annotation == null) {
+ return DEFAULT_FACTORY;
+ } else {
+ Class<? extends ParametersRunnerFactory> factoryClass = annotation
+ .value();
+ return factoryClass.newInstance();
}
}
- private void validatePublicStaticVoidMethods(
- Class<? extends Annotation> annotation, Integer parameterCount,
- List<Throwable> errors) {
- List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(annotation);
- for (FrameworkMethod fm : methods) {
- fm.validatePublicVoid(true, errors);
- if (parameterCount != null) {
- int methodParameterCount = fm.getMethod().getParameterTypes().length;
- if (methodParameterCount != 0 && methodParameterCount != parameterCount) {
- errors.add(new Exception("Method " + fm.getName()
- + "() should have 0 or " + parameterCount + " parameter(s)"));
- }
- }
- }
+ @Override
+ protected List<Runner> getChildren() {
+ return runners;
}
- private static class AssumptionViolationRunner extends Runner {
- private final Description description;
- private final AssumptionViolatedException exception;
-
- AssumptionViolationRunner(TestClass testClass, String methodName,
- AssumptionViolatedException exception) {
- this.description = Description
- .createTestDescription(testClass.getJavaClass(),
- methodName + "() assumption violation");
- this.exception = exception;
- }
-
- @Override
- public Description getDescription() {
- return description;
- }
-
- @Override
- public void run(RunNotifier notifier) {
- notifier.fireTestAssumptionFailed(new Failure(description, exception));
- }
+ private TestWithParameters createTestWithNotNormalizedParameters(
+ String pattern, int index, Object parametersOrSingleParameter) {
+ Object[] parameters= (parametersOrSingleParameter instanceof Object[]) ? (Object[]) parametersOrSingleParameter
+ : new Object[] { parametersOrSingleParameter };
+ return createTestWithParameters(getTestClass(), pattern, index,
+ parameters);
}
- private static class RunnersFactory {
- private static final ParametersRunnerFactory DEFAULT_FACTORY = new BlockJUnit4ClassRunnerWithParametersFactory();
-
- private final TestClass testClass;
- private final FrameworkMethod parametersMethod;
- private final List<Object> allParameters;
- private final int parameterCount;
- private final Runner runnerOverride;
-
- private RunnersFactory(Class<?> klass) throws Throwable {
- testClass = new TestClass(klass);
- parametersMethod = getParametersMethod(testClass);
- List<Object> allParametersResult;
- AssumptionViolationRunner assumptionViolationRunner = null;
- try {
- allParametersResult = allParameters(testClass, parametersMethod);
- } catch (AssumptionViolatedException e) {
- allParametersResult = Collections.emptyList();
- assumptionViolationRunner = new AssumptionViolationRunner(testClass,
- parametersMethod.getName(), e);
- }
- allParameters = allParametersResult;
- runnerOverride = assumptionViolationRunner;
- parameterCount =
- allParameters.isEmpty() ? 0 : normalizeParameters(allParameters.get(0)).length;
- }
-
- private List<Runner> createRunners() throws Exception {
- if (runnerOverride != null) {
- return Collections.singletonList(runnerOverride);
- }
- Parameters parameters = parametersMethod.getAnnotation(Parameters.class);
- return Collections.unmodifiableList(createRunnersForParameters(
- allParameters, parameters.name(),
- getParametersRunnerFactory()));
- }
-
- private ParametersRunnerFactory getParametersRunnerFactory()
- throws InstantiationException, IllegalAccessException {
- UseParametersRunnerFactory annotation = testClass
- .getAnnotation(UseParametersRunnerFactory.class);
- if (annotation == null) {
- return DEFAULT_FACTORY;
- } else {
- Class<? extends ParametersRunnerFactory> factoryClass = annotation
- .value();
- return factoryClass.newInstance();
- }
- }
-
- private TestWithParameters createTestWithNotNormalizedParameters(
- String pattern, int index, Object parametersOrSingleParameter) {
- Object[] parameters = normalizeParameters(parametersOrSingleParameter);
- return createTestWithParameters(testClass, pattern, index, parameters);
- }
-
- private static Object[] normalizeParameters(Object parametersOrSingleParameter) {
- return (parametersOrSingleParameter instanceof Object[]) ? (Object[]) parametersOrSingleParameter
- : new Object[] { parametersOrSingleParameter };
+ @SuppressWarnings("unchecked")
+ private Iterable<Object> allParameters() throws Throwable {
+ Object parameters = getParametersMethod().invokeExplosively(null);
+ if (parameters instanceof Iterable) {
+ return (Iterable<Object>) parameters;
+ } else if (parameters instanceof Object[]) {
+ return Arrays.asList((Object[]) parameters);
+ } else {
+ throw parametersMethodReturnedWrongType();
}
+ }
- @SuppressWarnings("unchecked")
- private static List<Object> allParameters(
- TestClass testClass, FrameworkMethod parametersMethod) throws Throwable {
- Object parameters = parametersMethod.invokeExplosively(null);
- if (parameters instanceof List) {
- return (List<Object>) parameters;
- } else if (parameters instanceof Collection) {
- return new ArrayList<Object>((Collection<Object>) parameters);
- } else if (parameters instanceof Iterable) {
- List<Object> result = new ArrayList<Object>();
- for (Object entry : ((Iterable<Object>) parameters)) {
- result.add(entry);
- }
- return result;
- } else if (parameters instanceof Object[]) {
- return Arrays.asList((Object[]) parameters);
- } else {
- throw parametersMethodReturnedWrongType(testClass, parametersMethod);
+ private FrameworkMethod getParametersMethod() throws Exception {
+ List<FrameworkMethod> methods = getTestClass().getAnnotatedMethods(
+ Parameters.class);
+ for (FrameworkMethod each : methods) {
+ if (each.isStatic() && each.isPublic()) {
+ return each;
}
}
- private static FrameworkMethod getParametersMethod(TestClass testClass) throws Exception {
- List<FrameworkMethod> methods = testClass
- .getAnnotatedMethods(Parameters.class);
- for (FrameworkMethod each : methods) {
- if (each.isStatic() && each.isPublic()) {
- return each;
- }
- }
-
- throw new Exception("No public static parameters method on class "
- + testClass.getName());
- }
+ throw new Exception("No public static parameters method on class "
+ + getTestClass().getName());
+ }
- private List<Runner> createRunnersForParameters(
- Iterable<Object> allParameters, String namePattern,
- ParametersRunnerFactory runnerFactory) throws Exception {
- try {
- List<TestWithParameters> tests = createTestsForParameters(
- allParameters, namePattern);
- List<Runner> runners = new ArrayList<Runner>();
- for (TestWithParameters test : tests) {
- runners.add(runnerFactory
- .createRunnerForTestWithParameters(test));
- }
- return runners;
- } catch (ClassCastException e) {
- throw parametersMethodReturnedWrongType(testClass, parametersMethod);
+ private List<Runner> createRunnersForParameters(
+ Iterable<Object> allParameters, String namePattern,
+ ParametersRunnerFactory runnerFactory)
+ throws InitializationError,
+ Exception {
+ try {
+ List<TestWithParameters> tests = createTestsForParameters(
+ allParameters, namePattern);
+ List<Runner> runners = new ArrayList<Runner>();
+ for (TestWithParameters test : tests) {
+ runners.add(runnerFactory
+ .createRunnerForTestWithParameters(test));
}
+ return runners;
+ } catch (ClassCastException e) {
+ throw parametersMethodReturnedWrongType();
}
+ }
- private List<TestWithParameters> createTestsForParameters(
- Iterable<Object> allParameters, String namePattern)
- throws Exception {
- int i = 0;
- List<TestWithParameters> children = new ArrayList<TestWithParameters>();
- for (Object parametersOfSingleTest : allParameters) {
- children.add(createTestWithNotNormalizedParameters(namePattern,
- i++, parametersOfSingleTest));
- }
- return children;
+ private List<TestWithParameters> createTestsForParameters(
+ Iterable<Object> allParameters, String namePattern)
+ throws Exception {
+ int i = 0;
+ List<TestWithParameters> children = new ArrayList<TestWithParameters>();
+ for (Object parametersOfSingleTest : allParameters) {
+ children.add(createTestWithNotNormalizedParameters(namePattern,
+ i++, parametersOfSingleTest));
}
+ return children;
+ }
- private static Exception parametersMethodReturnedWrongType(
- TestClass testClass, FrameworkMethod parametersMethod) throws Exception {
- String className = testClass.getName();
- String methodName = parametersMethod.getName();
- String message = MessageFormat.format(
- "{0}.{1}() must return an Iterable of arrays.", className,
- methodName);
- return new Exception(message);
- }
+ private Exception parametersMethodReturnedWrongType() throws Exception {
+ String className = getTestClass().getName();
+ String methodName = getParametersMethod().getName();
+ String message = MessageFormat.format(
+ "{0}.{1}() must return an Iterable of arrays.",
+ className, methodName);
+ return new Exception(message);
+ }
- private TestWithParameters createTestWithParameters(
- TestClass testClass, String pattern, int index,
- Object[] parameters) {
- String finalPattern = pattern.replaceAll("\\{index\\}",
- Integer.toString(index));
- String name = MessageFormat.format(finalPattern, parameters);
- return new TestWithParameters("[" + name + "]", testClass,
- Arrays.asList(parameters));
- }
+ private static TestWithParameters createTestWithParameters(
+ TestClass testClass, String pattern, int index, Object[] parameters) {
+ String finalPattern = pattern.replaceAll("\\{index\\}",
+ Integer.toString(index));
+ String name = MessageFormat.format(finalPattern, parameters);
+ return new TestWithParameters("[" + name + "]", testClass,
+ Arrays.asList(parameters));
}
}