One of the many excellent new features of JUnit 4 is parameterized tests. These are data-driven tests where a test case runs repeatedly against a collection of test data, as if each run were its own test case.
A standard example:
@RunWith(Parameterized.class) public class ExampleDataDrivenTest { public static final class Data { private final String name; public Data(final String name) { this.name = name; } @Override public String toString() { return name; } } private final List<Data> data; public ExampleDataDrivenTest(final Data datum1, final Data datum2) { System.out.println("ExampleDataDrivenTest"); this.data = asList(datum1, datum2); } @Test public void dumpData() { for (final Data datum : data) System.out.println("datum = " + datum); } @Parameters public static Collection<Data[]> data() { final Data[][] data = new Data[][]{ {new Data("apple"), new Data("core")}}; return asList(data); } }
This produces:
ExampleDataDrivenTest datum = apple datum = core
This works great for a fixed number of test data, but I want to test a variable number of data. The change is straight-forward once you recall that the varargs Java language feature is implemented as an array:
@RunWith(Parameterized.class) public class ExampleDataDrivenTest { public static final class Data { private final String name; public Data(final String name) { this.name = name; } @Override public String toString() { return name; } } private final List<Data> data; public ExampleDataDrivenTest(final Data... data) { System.out.println("ExampleDataDrivenTest"); this.data = asList(data); } @Test public void dumpData() { for (final Data datum : data) System.out.println("datum = " + datum); } @Parameters public static Collection<Data[][]> data() { final Data[][][] data = new Data[][][]{ {{new Data("apple"), new Data("core")}}}; return asList(data); } }
Reflect on the constructor and you see:
public ExampleDataDrivenTest(ExampleDataDrivenTest$Data[])
This makes the change more obvious.
I can now write my annotated parameters as:
@Parameters public static Collection<Data[][]> data() { final Data[][][] data = new Data[][][]{{{ /* no data */ }}, {{new Data("apple"), new Data("core")}}, {{new Data("baltimore")}}}; return asList(data); }
To produce:
ExampleDataDrivenTest ExampleDataDrivenTest datum = apple datum = core ExampleDataDrivenTest datum = baltimore
9 comments:
Wow, this is seriously convoluted, and it violates the DRY principle in many ways. Compare to TestNG's version:
@DataProvider
public Object[][] parameters() {
return new Object[][] {
new Object[] { new Data("apple"), new Data("core") },
}
}
@Test(dataProvider = "parameters")
public void f(Data d1, Data d2) {
// ...
}
Why does JUnit make this simple concept so complicated?!?
Anonymous,
It is not so complicated. Your TestNG example is not using varargs. :)
varargs is already supported, nothing impressive about it, it's all reflection based.
Are you seriously saying the JUnit example is as straightforward as TestNG's?
If you are, then we definitely have different standards for readability.
I was not planning on a religious war of unit testing frameworks. I prefer JUnit; there is nothing wrong with TestNG.
I consider TestNG over-engineered, but that is a matter of taste.
Very interesting!
Thanks a lot, I found this while looking for an example of parameterized tests, better than the one in junit4 javadoc.
Pretty good examples!
it's good to see this information in your post, i was looking the same but there was not any proper resource, thanx now i have the link which i was looking for my research.
Thanks for so good and informative blog about JUint.
I have to agree with poster writing the first comment. If you have independent tests by running the same test method with different data TestNG will run the test method several times and report its result separately for each run. In case of JUnit concept you have to implement that your own. Furthermore you will not get any detailed information about which test failed with given test data on the test result. You will only see that test method XYZ has failed running with data ABC. If following tests were successful is unknown.
Post a Comment