Is it possible to run a parameterized test class with JUnitCore API?
I've a class under test called Fibonacci, a parameterized test class called TestFibonacci, and a simple Java class (JUnitParameterized) which executes the TestFibonacci class using JUnitCore API. If I execute TestFibonacci with JUnit plugin or command line, it passes. However, when I execute it with my JUnitParameterized class it fails.
Class Under Test
public class Fibonacci {
public static int compute(int n) {
if (n <= 1) {
return n;
}
return compute(n-1) + compute(n-2);
}
}
Test Class
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
@RunWith(Parameterized.class)
public class TestFibonacci {
@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 input;
private int expected;
public TestFibonacci(int input, int expected) {
this.input = input;
this.expected = expected;
}
@Test
public void test() {
assertEquals(expected, Fibonacci.compute(input));
}
}
Java program
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;
public class JUnitParameterized {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> testClass = JUnitParameterized.class.getClassLoader().loadClass(TestFibonacci.class.getCanonicalName());
Result result = (new JUnitCore()).run(Request.method(testClass, "test"));
System.out.println("Number of tests run: " + result.getRunCount());
System.out.println("The number of tests that failed during the run: " + result.getFailureCount());
System.out.println("The number of milliseconds it took to run the entire suite to run: " + result.getRunTime());
System.out.println("" + (result.wasSuccessful() == true ? "Passed :)" : "Failed :("));
}
}
When a JUnit test class is annotated with @Parameterized
, the test method name as a description is enriched with a number in braces, colon, and the substituted name
you're providing in the @Parameters
annotation.
In your case, to execute single test, that is with one parameters set, you would
Result result = (new JUnitCore()).run(Request.method(TestFibonacci.class, "test[6: fib(6)=8]"));
In this case, the 6th parameter set is provided (starting with zero).
Note that, you must match exactly the numbers you're providing in the method name with what you declared as parameters. The sequence number also matters. As such following would not work:
"test[3: fib(6)=8]" (wrong sequence .. <6, 8> pair is 6th, not 3rd)
"test[6: fib(50)=100]" (the pair <50, 100> is not declared in parameters)
To avoid unnecessary parsing of the @Parameters(name=?)
value, I would suggest to just declare the parameters without the name
:
@Parameters // no name=?
public static Iterable<Object[]> data() {
return Arrays.asList(
new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
}
And then the test method description is just test[6]
:
Result result = (new JUnitCore()).run(Request.method(TestFibonacci.class, "test[6]"));
To run a single test method with all the parameters, I would suggest to do it in a cycle (and possibly aggregate the results):
int parametersCount = Request.aClass(TestFibonacci.class).getRunner().getDescription().getChildren().size();
for (int i = 0; i < parametersCount; ++i) {
Result result = (new JUnitCore()).run(Request.method(testClass, "testFloat[" + i + "]"));
System.out.println("Result " + result.wasSuccessful());
}