Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge pull request #393 from stefanbirkner/Parameterized

Add names for parameterized tests. Fixes #24 and #44.
  • Loading branch information...
commit 3a5c9f2731462e36dd1c173ea8840d7b9b34b0ab 2 parents 560322d + 6a3cec9
David Saff authored
107 src/main/java/org/junit/runners/Parameterized.java
... ... @@ -1,12 +1,11 @@
1 1 package org.junit.runners;
2 2
3   -import static java.lang.String.format;
4   -
5 3 import java.lang.annotation.Annotation;
6 4 import java.lang.annotation.ElementType;
7 5 import java.lang.annotation.Retention;
8 6 import java.lang.annotation.RetentionPolicy;
9 7 import java.lang.annotation.Target;
  8 +import java.text.MessageFormat;
10 9 import java.util.ArrayList;
11 10 import java.util.Collections;
12 11 import java.util.List;
@@ -29,7 +28,7 @@
29 28 * <pre>
30 29 * &#064;RunWith(Parameterized.class)
31 30 * public class FibonacciTest {
32   - * &#064;Parameters
  31 + * &#064;Parameters(name= &quot;{index}: fib({0})={1}&quot;)
33 32 * public static Iterable&lt;Object[]&gt; data() {
34 33 * return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
35 34 * { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
@@ -55,6 +54,24 @@
55 54 * Each instance of <code>FibonacciTest</code> will be constructed using the
56 55 * two-argument constructor and the data values in the
57 56 * <code>&#064;Parameters</code> method.
  57 + *
  58 + * <p>
  59 + * In order that you can easily identify the individual tests, you may provide a
  60 + * name for the <code>&#064;Parameters</code> annotation. This name is allowed
  61 + * to contain placeholders, which are replaced at runtime. The placeholders are
  62 + * <dl>
  63 + * <dt>{index}</dt>
  64 + * <dd>the current parameter index</dd>
  65 + * <dt>{0}</dt>
  66 + * <dd>the first parameter value</dd>
  67 + * <dt>{1}</dt>
  68 + * <dd>the second parameter value</dd>
  69 + * <dt>...</dt>
  70 + * <dd></dd>
  71 + * </dl>
  72 + * In the example given above, the <code>Parameterized</code> runner creates
  73 + * names like <code>[1: fib(3)=2]</code>. If you don't use the name parameter,
  74 + * then the current parameter index is used as name.
58 75 * </p>
59 76 */
60 77 public class Parameterized extends Suite {
@@ -65,19 +82,41 @@
65 82 @Retention(RetentionPolicy.RUNTIME)
66 83 @Target(ElementType.METHOD)
67 84 public static @interface Parameters {
  85 + /**
  86 + * <p>
  87 + * Optional pattern to derive the test's name from the parameters. Use
  88 + * numbers in braces to refer to the parameters or the additional data
  89 + * as follows:
  90 + * </p>
  91 + *
  92 + * <pre>
  93 + * {index} - the current parameter index
  94 + * {0} - the first parameter value
  95 + * {1} - the second parameter value
  96 + * etc...
  97 + * </pre>
  98 + * <p>
  99 + * Default value is "{index}" for compatibility with previous JUnit
  100 + * versions.
  101 + * </p>
  102 + *
  103 + * @return {@link MessageFormat} pattern string, except the index
  104 + * placeholder.
  105 + * @see MessageFormat
  106 + */
  107 + String name() default "{index}";
68 108 }
69 109
70   - private class TestClassRunnerForParameters extends
71   - BlockJUnit4ClassRunner {
72   - private final int fParameterSetNumber;
73   -
  110 + private class TestClassRunnerForParameters extends BlockJUnit4ClassRunner {
74 111 private final Object[] fParameters;
75 112
76   - TestClassRunnerForParameters(Class<?> type, Object[] parameters, int i)
77   - throws InitializationError {
  113 + private final String fName;
  114 +
  115 + TestClassRunnerForParameters(Class<?> type, Object[] parameters,
  116 + String name) throws InitializationError {
78 117 super(type);
79 118 fParameters= parameters;
80   - fParameterSetNumber= i;
  119 + fName= name;
81 120 }
82 121
83 122 @Override
@@ -87,13 +126,12 @@ public Object createTest() throws Exception {
87 126
88 127 @Override
89 128 protected String getName() {
90   - return String.format("[%s]", fParameterSetNumber);
  129 + return fName;
91 130 }
92 131
93 132 @Override
94   - protected String testName(final FrameworkMethod method) {
95   - return String.format("%s[%s]", method.getName(),
96   - fParameterSetNumber);
  133 + protected String testName(FrameworkMethod method) {
  134 + return method.getName() + getName();
97 135 }
98 136
99 137 @Override
@@ -105,22 +143,26 @@ protected void validateConstructor(List<Throwable> errors) {
105 143 protected Statement classBlock(RunNotifier notifier) {
106 144 return childrenInvoker(notifier);
107 145 }
108   -
  146 +
109 147 @Override
110 148 protected Annotation[] getRunnerAnnotations() {
111 149 return new Annotation[0];
112 150 }
113 151 }
114 152
  153 + private static final List<Runner> NO_RUNNERS= Collections
  154 + .<Runner> emptyList();
  155 +
115 156 private final ArrayList<Runner> runners= new ArrayList<Runner>();
116 157
117 158 /**
118 159 * Only called reflectively. Do not use programmatically.
119 160 */
120 161 public Parameterized(Class<?> klass) throws Throwable {
121   - super(klass, Collections.<Runner> emptyList());
122   - Iterable<Object[]> allParameters= getAllParameters();
123   - createRunnersForParameters(allParameters);
  162 + super(klass, NO_RUNNERS);
  163 + Parameters parameters= getParametersMethod().getAnnotation(
  164 + Parameters.class);
  165 + createRunnersForParameters(allParameters(), parameters.name());
124 166 }
125 167
126 168 @Override
@@ -129,8 +171,7 @@ public Parameterized(Class<?> klass) throws Throwable {
129 171 }
130 172
131 173 @SuppressWarnings("unchecked")
132   - private Iterable<Object[]> getAllParameters()
133   - throws Throwable {
  174 + private Iterable<Object[]> allParameters() throws Throwable {
134 175 Object parameters= getParametersMethod().invokeExplosively(null);
135 176 if (parameters instanceof Iterable)
136 177 return (Iterable<Object[]>) parameters;
@@ -138,10 +179,9 @@ public Parameterized(Class<?> klass) throws Throwable {
138 179 throw parametersMethodReturnedWrongType();
139 180 }
140 181
141   - private FrameworkMethod getParametersMethod()
142   - throws Exception {
143   - List<FrameworkMethod> methods= getTestClass()
144   - .getAnnotatedMethods(Parameters.class);
  182 + private FrameworkMethod getParametersMethod() throws Exception {
  183 + List<FrameworkMethod> methods= getTestClass().getAnnotatedMethods(
  184 + Parameters.class);
145 185 for (FrameworkMethod each : methods) {
146 186 if (each.isStatic() && each.isPublic())
147 187 return each;
@@ -151,14 +191,15 @@ private FrameworkMethod getParametersMethod()
151 191 + getTestClass().getName());
152 192 }
153 193
154   - private void createRunnersForParameters(Iterable<Object[]> allParameters)
155   - throws InitializationError, Exception {
  194 + private void createRunnersForParameters(Iterable<Object[]> allParameters,
  195 + String namePattern) throws InitializationError, Exception {
156 196 try {
157 197 int i= 0;
158 198 for (Object[] parametersOfSingleTest : allParameters) {
  199 + String name= nameFor(namePattern, i, parametersOfSingleTest);
159 200 TestClassRunnerForParameters runner= new TestClassRunnerForParameters(
160 201 getTestClass().getJavaClass(), parametersOfSingleTest,
161   - i);
  202 + name);
162 203 runners.add(runner);
163 204 ++i;
164 205 }
@@ -167,11 +208,19 @@ private void createRunnersForParameters(Iterable<Object[]> allParameters)
167 208 }
168 209 }
169 210
  211 + private String nameFor(String namePattern, int index, Object[] parameters) {
  212 + String finalPattern= namePattern.replaceAll("\\{index\\}",
  213 + Integer.toString(index));
  214 + String name= MessageFormat.format(finalPattern, parameters);
  215 + return "[" + name + "]";
  216 + }
  217 +
170 218 private Exception parametersMethodReturnedWrongType() throws Exception {
171 219 String className= getTestClass().getName();
172 220 String methodName= getParametersMethod().getName();
173   - String message= format("%s.%s() must return an Iterable of arrays.",
  221 + String message= MessageFormat.format(
  222 + "{0}.{1}() must return an Iterable of arrays.",
174 223 className, methodName);
175 224 return new Exception(message);
176 225 }
177   -}
  226 +}
36 src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
@@ -25,15 +25,15 @@
25 25 public class ParameterizedTestTest {
26 26 @RunWith(Parameterized.class)
27 27 static public class FibonacciTest {
28   - @Parameters
  28 + @Parameters(name= "{index}: fib({0})={1}")
29 29 public static Iterable<Object[]> data() {
30 30 return Arrays.asList(new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 },
31 31 { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
32 32 }
33 33
34   - private int fInput;
  34 + private final int fInput;
35 35
36   - private int fExpected;
  36 + private final int fExpected;
37 37
38 38 public FibonacciTest(int input, int expected) {
39 39 fInput= input;
@@ -61,7 +61,7 @@ public void count() {
61 61 public void failuresNamedCorrectly() {
62 62 Result result= JUnitCore.runClasses(FibonacciTest.class);
63 63 assertEquals(
64   - String.format("test[1](%s)", FibonacciTest.class.getName()),
  64 + "test[1: fib(1)=1](" + FibonacciTest.class.getName() + ")",
65 65 result.getFailures().get(0).getTestHeader());
66 66 }
67 67
@@ -75,7 +75,31 @@ public void countBeforeRun() throws Exception {
75 75 public void plansNamedCorrectly() throws Exception {
76 76 Runner runner= Request.aClass(FibonacciTest.class).getRunner();
77 77 Description description= runner.getDescription();
78   - assertEquals("[0]", description.getChildren().get(0).getDisplayName());
  78 + assertEquals("[0: fib(0)=0]", description.getChildren().get(0)
  79 + .getDisplayName());
  80 + }
  81 +
  82 + @RunWith(Parameterized.class)
  83 + public static class ParameterizedWithoutSpecialTestname {
  84 + @Parameters
  85 + public static Collection<Object[]> data() {
  86 + return Arrays.asList(new Object[][] { { 3 }, { 3 } });
  87 + }
  88 +
  89 + public ParameterizedWithoutSpecialTestname(Object something) {
  90 + }
  91 +
  92 + @Test
  93 + public void testSomething() {
  94 + }
  95 + }
  96 +
  97 + @Test
  98 + public void usesIndexAsTestName() {
  99 + Runner runner= Request
  100 + .aClass(ParameterizedWithoutSpecialTestname.class).getRunner();
  101 + Description description= runner.getDescription();
  102 + assertEquals("[1]", description.getChildren().get(1).getDisplayName());
79 103 }
80 104
81 105 private static String fLog;
@@ -230,4 +254,4 @@ public void aTest() {
230 254 public void exceptionWhenPrivateConstructor() throws Throwable {
231 255 new Parameterized(PrivateConstructor.class);
232 256 }
233   -}
  257 +}

0 comments on commit 3a5c9f2

Please sign in to comment.
Something went wrong with that request. Please try again.