Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add names for parameterized tests. Fixes #24 and #44. #393

Merged
merged 4 commits into from

3 participants

@stefanbirkner
Collaborator

In order that you can easily identify individual test, you may provide a name for the Parameters annotation.
@Parameters(name="my test")
This name is allowed to contain placeholders, which are replaced at runtime. The placeholders are

  • {index} - the current parameter index
  • {0} - the first parameter
  • {1} - the second parameter
  • ... - the other parameters If you don't use the name parameter, then the current parameter index is used as name.

Example:
When you use @Parameters(name="fib({0})={1}") with the Fibonacci example, then you get test names like "fib(3)=2".

This feature is based on the work of Dimitar Dimitrov (pull request#145). Thank you.

@stefanbirkner stefanbirkner Add names for parameterized tests. Fixes #24 and #44.
In order that you can easily identify individual test, you may provide
a name for the Parameters annotation.
 @Parameters(name="my test")
This name is allowed to contain placeholders, which are replaced at
runtime. The placeholders are
* {index} - the current parameter index
* {0} - the first parameter
* {1} - the second parameter
* ... - the other parameters
If you don't use the name parameter, then the current parameter index
is used as name.

Example:
When you use @Parameters(name="fib({0})={1}") with the Fibonacci
example, then you get test names like "fib(3)=2".

This feature is based on the work of Dimitar Dimitrov (pull request
#145).
Thank
you.
e0cddcd
@dsaff dsaff commented on the diff
src/main/java/org/junit/runners/Parameterized.java
((6 lines not shown))
@Override
protected Annotation[] getRunnerAnnotations() {
return new Annotation[0];
}
}
+ private static final List<Runner> NO_RUNNERS= Collections
+ .<Runner> emptyList();
@dsaff Owner
dsaff added a note

What column limit are you formatting with? Some of these lines seem to be wrapped pretty early

@stefanbirkner Collaborator

I use the standard settings: org.eclipse.jdt.core.formatter.lineSplit=80.

@dsaff Owner
dsaff added a note

OK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/main/java/org/junit/runners/Parameterized.java
@@ -167,11 +210,17 @@ private void createRunnersForParameters(Iterable<Object[]> allParameters)
}
}
+ private String nameFor(String namePattern, int index, Object[] parameters) {
+ String finalPattern= namePattern.replaceAll("\\{index\\}",
+ Integer.toString(index));
+ return format(finalPattern, parameters);
@dsaff Owner
dsaff added a note

I'd rather explicitly use MessageFormat.format here, rather than statically importing the method. I know this is a change from precedent, but I think it's an improvement.

@stefanbirkner Collaborator

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
...unit/tests/running/classes/ParameterizedTestTest.java
@@ -25,15 +25,15 @@
public class ParameterizedTestTest {
@RunWith(Parameterized.class)
static public class FibonacciTest {
- @Parameters
+ @Parameters(name= "[{index}: fib({0})={1}]")
@dsaff Owner
dsaff added a note

I wonder, should we just supply the brackets ourselves? That is, should the above read

@Parameters(name= "{index}: fib({0})={1}")

, but the test would be otherwise unchanged?

@stefanbirkner Collaborator

The current solution enables the user to define the complete name, which is equal to the description's display name. This possibility vanishes, when we provide the brackets ourselves. Therefore I prefer to not supply the brackets.

@dsaff Owner
dsaff added a note

I understand that. On the other hand, by strongly encouraging a standard, downstream tools can expect a standard (for example, to find the method name associated with a test run, throw away everything in brackets.) This has been a (somewhat accidental) win for standard JUnit tests, as well, which are usually parseable into class and method names using simple rules.

Any chance I can win you over? :-)

@stefanbirkner Collaborator

You convinced me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@dsaff dsaff commented on the diff
src/main/java/org/junit/runners/Parameterized.java
@@ -167,11 +208,19 @@ private void createRunnersForParameters(Iterable<Object[]> allParameters)
}
}
+ private String nameFor(String namePattern, int index, Object[] parameters) {
+ String finalPattern= namePattern.replaceAll("\\{index\\}",
+ Integer.toString(index));
+ String name= MessageFormat.format(finalPattern, parameters);
+ return "[" + name + "]";
@dsaff Owner
dsaff added a note

Should the added brackets be mentioned in the javadoc?

@stefanbirkner Collaborator

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@dsaff dsaff merged commit 3a5c9f2 into junit-team:master
@dsaff
Owner

Many thanks!

@marcphilipp
Collaborator

Running the example from the Javadoc in Eclipse will show this 7-year-old bug:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=102512
:-/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 2, 2012
  1. @stefanbirkner

    Add names for parameterized tests. Fixes #24 and #44.

    stefanbirkner authored
    In order that you can easily identify individual test, you may provide
    a name for the Parameters annotation.
     @Parameters(name="my test")
    This name is allowed to contain placeholders, which are replaced at
    runtime. The placeholders are
    * {index} - the current parameter index
    * {0} - the first parameter
    * {1} - the second parameter
    * ... - the other parameters
    If you don't use the name parameter, then the current parameter index
    is used as name.
    
    Example:
    When you use @Parameters(name="fib({0})={1}") with the Fibonacci
    example, then you get test names like "fib(3)=2".
    
    This feature is based on the work of Dimitar Dimitrov (pull request
    #145).
    Thank
    you.
Commits on Mar 5, 2012
  1. @stefanbirkner
  2. @stefanbirkner
Commits on Apr 3, 2012
  1. @stefanbirkner
This page is out of date. Refresh to see the latest.
View
107 src/main/java/org/junit/runners/Parameterized.java
@@ -1,12 +1,11 @@
package org.junit.runners;
-import static java.lang.String.format;
-
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.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -29,7 +28,7 @@
* <pre>
* &#064;RunWith(Parameterized.class)
* public class FibonacciTest {
- * &#064;Parameters
+ * &#064;Parameters(name= &quot;{index}: fib({0})={1}&quot;)
* 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 } });
@@ -55,6 +54,24 @@
* 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
+ * name for the <code>&#064;Parameters</code> annotation. This name is allowed
+ * to contain placeholders, which are replaced at runtime. The placeholders are
+ * <dl>
+ * <dt>{index}</dt>
+ * <dd>the current parameter index</dd>
+ * <dt>{0}</dt>
+ * <dd>the first parameter value</dd>
+ * <dt>{1}</dt>
+ * <dd>the second parameter value</dd>
+ * <dt>...</dt>
+ * <dd></dd>
+ * </dl>
+ * In the example given above, the <code>Parameterized</code> runner creates
+ * 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>
*/
public class Parameterized extends Suite {
@@ -65,19 +82,41 @@
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface Parameters {
+ /**
+ * <p>
+ * Optional pattern to derive the test's name from the parameters. Use
+ * numbers in braces to refer to the parameters or the additional data
+ * as follows:
+ * </p>
+ *
+ * <pre>
+ * {index} - the current parameter index
+ * {0} - the first parameter value
+ * {1} - the second parameter value
+ * etc...
+ * </pre>
+ * <p>
+ * Default value is "{index}" for compatibility with previous JUnit
+ * versions.
+ * </p>
+ *
+ * @return {@link MessageFormat} pattern string, except the index
+ * placeholder.
+ * @see MessageFormat
+ */
+ String name() default "{index}";
}
- private class TestClassRunnerForParameters extends
- BlockJUnit4ClassRunner {
- private final int fParameterSetNumber;
-
+ private class TestClassRunnerForParameters extends BlockJUnit4ClassRunner {
private final Object[] fParameters;
- TestClassRunnerForParameters(Class<?> type, Object[] parameters, int i)
- throws InitializationError {
+ private final String fName;
+
+ TestClassRunnerForParameters(Class<?> type, Object[] parameters,
+ String name) throws InitializationError {
super(type);
fParameters= parameters;
- fParameterSetNumber= i;
+ fName= name;
}
@Override
@@ -87,13 +126,12 @@ public Object createTest() throws Exception {
@Override
protected String getName() {
- return String.format("[%s]", fParameterSetNumber);
+ return fName;
}
@Override
- protected String testName(final FrameworkMethod method) {
- return String.format("%s[%s]", method.getName(),
- fParameterSetNumber);
+ protected String testName(FrameworkMethod method) {
+ return method.getName() + getName();
}
@Override
@@ -105,22 +143,26 @@ protected void validateConstructor(List<Throwable> errors) {
protected Statement classBlock(RunNotifier notifier) {
return childrenInvoker(notifier);
}
-
+
@Override
protected Annotation[] getRunnerAnnotations() {
return new Annotation[0];
}
}
+ private static final List<Runner> NO_RUNNERS= Collections
+ .<Runner> emptyList();
@dsaff Owner
dsaff added a note

What column limit are you formatting with? Some of these lines seem to be wrapped pretty early

@stefanbirkner Collaborator

I use the standard settings: org.eclipse.jdt.core.formatter.lineSplit=80.

@dsaff Owner
dsaff added a note

OK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
private final ArrayList<Runner> runners= new ArrayList<Runner>();
/**
* Only called reflectively. Do not use programmatically.
*/
public Parameterized(Class<?> klass) throws Throwable {
- super(klass, Collections.<Runner> emptyList());
- Iterable<Object[]> allParameters= getAllParameters();
- createRunnersForParameters(allParameters);
+ super(klass, NO_RUNNERS);
+ Parameters parameters= getParametersMethod().getAnnotation(
+ Parameters.class);
+ createRunnersForParameters(allParameters(), parameters.name());
}
@Override
@@ -129,8 +171,7 @@ public Parameterized(Class<?> klass) throws Throwable {
}
@SuppressWarnings("unchecked")
- private Iterable<Object[]> getAllParameters()
- throws Throwable {
+ private Iterable<Object[]> allParameters() throws Throwable {
Object parameters= getParametersMethod().invokeExplosively(null);
if (parameters instanceof Iterable)
return (Iterable<Object[]>) parameters;
@@ -138,10 +179,9 @@ public Parameterized(Class<?> klass) throws Throwable {
throw parametersMethodReturnedWrongType();
}
- private FrameworkMethod getParametersMethod()
- throws Exception {
- List<FrameworkMethod> methods= getTestClass()
- .getAnnotatedMethods(Parameters.class);
+ private FrameworkMethod getParametersMethod() throws Exception {
+ List<FrameworkMethod> methods= getTestClass().getAnnotatedMethods(
+ Parameters.class);
for (FrameworkMethod each : methods) {
if (each.isStatic() && each.isPublic())
return each;
@@ -151,14 +191,15 @@ private FrameworkMethod getParametersMethod()
+ getTestClass().getName());
}
- private void createRunnersForParameters(Iterable<Object[]> allParameters)
- throws InitializationError, Exception {
+ private void createRunnersForParameters(Iterable<Object[]> allParameters,
+ String namePattern) throws InitializationError, Exception {
try {
int i= 0;
for (Object[] parametersOfSingleTest : allParameters) {
+ String name= nameFor(namePattern, i, parametersOfSingleTest);
TestClassRunnerForParameters runner= new TestClassRunnerForParameters(
getTestClass().getJavaClass(), parametersOfSingleTest,
- i);
+ name);
runners.add(runner);
++i;
}
@@ -167,11 +208,19 @@ private void createRunnersForParameters(Iterable<Object[]> allParameters)
}
}
+ private String nameFor(String namePattern, int index, Object[] parameters) {
+ String finalPattern= namePattern.replaceAll("\\{index\\}",
+ Integer.toString(index));
+ String name= MessageFormat.format(finalPattern, parameters);
+ return "[" + name + "]";
@dsaff Owner
dsaff added a note

Should the added brackets be mentioned in the javadoc?

@stefanbirkner Collaborator

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ }
+
private Exception parametersMethodReturnedWrongType() throws Exception {
String className= getTestClass().getName();
String methodName= getParametersMethod().getName();
- String message= format("%s.%s() must return an Iterable of arrays.",
+ String message= MessageFormat.format(
+ "{0}.{1}() must return an Iterable of arrays.",
className, methodName);
return new Exception(message);
}
-}
+}
View
36 src/test/java/org/junit/tests/running/classes/ParameterizedTestTest.java
@@ -25,15 +25,15 @@
public class ParameterizedTestTest {
@RunWith(Parameterized.class)
static public class FibonacciTest {
- @Parameters
+ @Parameters(name= "{index}: fib({0})={1}")
public static Iterable<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 final int fInput;
- private int fExpected;
+ private final int fExpected;
public FibonacciTest(int input, int expected) {
fInput= input;
@@ -61,7 +61,7 @@ public void count() {
public void failuresNamedCorrectly() {
Result result= JUnitCore.runClasses(FibonacciTest.class);
assertEquals(
- String.format("test[1](%s)", FibonacciTest.class.getName()),
+ "test[1: fib(1)=1](" + FibonacciTest.class.getName() + ")",
result.getFailures().get(0).getTestHeader());
}
@@ -75,7 +75,31 @@ public void countBeforeRun() throws Exception {
public void plansNamedCorrectly() throws Exception {
Runner runner= Request.aClass(FibonacciTest.class).getRunner();
Description description= runner.getDescription();
- assertEquals("[0]", description.getChildren().get(0).getDisplayName());
+ assertEquals("[0: fib(0)=0]", description.getChildren().get(0)
+ .getDisplayName());
+ }
+
+ @RunWith(Parameterized.class)
+ public static class ParameterizedWithoutSpecialTestname {
+ @Parameters
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] { { 3 }, { 3 } });
+ }
+
+ public ParameterizedWithoutSpecialTestname(Object something) {
+ }
+
+ @Test
+ public void testSomething() {
+ }
+ }
+
+ @Test
+ public void usesIndexAsTestName() {
+ Runner runner= Request
+ .aClass(ParameterizedWithoutSpecialTestname.class).getRunner();
+ Description description= runner.getDescription();
+ assertEquals("[1]", description.getChildren().get(1).getDisplayName());
}
private static String fLog;
@@ -230,4 +254,4 @@ public void aTest() {
public void exceptionWhenPrivateConstructor() throws Throwable {
new Parameterized(PrivateConstructor.class);
}
-}
+}
Something went wrong with that request. Please try again.