One of my favorite features of TestNG is its hip parametric testing ability, which allows you to create generic test cases and then vary the test values– you can use parameters from XML files or even use the DataProvider feature for a more rich parameter type. In fact, for awhile, because it’s my bag baby, I’ve been espousing TestNG’s out of the box parametric testing features as a reason to use TestNG as a opposed to JUnit for higher level testing. JUnit 4 , however, now supports parametric tests– and you’ll find that its parametric testing is rather similar to TestNG’s DataProvider.
For example, in TestNG, if I’d like to create a generic test and vary its parameters, I have to do three things:
- Create a generic test whose parameters are the parameterized values
- Create a
DataProvidermethod, which feeds the values for the test - Link the
DataProvidermethod to the test via the@Testannotation
Hence, I can create a copasetic generic test method as follows:
public void verifyHierarchies(Class clzz, String[] names)
throws Exception{
Hierarchy hier = HierarchyBuilder.buildHierarchy(clzz);
assertEquals(hier.getHierarchyClassNames(), names, "values were not equal");
}
Then I can create a feeder method as follows:
@DataProvider(name = "class-hierarchies")
public Object[][] dataValues(){
return new Object[][]{
{Vector.class, new String[] {"java.util.AbstractList",
"java.util.AbstractCollection"}},
{String.class, new String[] {}}
};
}
Note how I have to declare a name for DataProvider, in my case, I dub it class-hierarchies. I can now link the two methods by using the @Test annotation and setting the dataProvider value to the name of my feeder method:
@Test(dataProvider = "class-hierarchies")
That was fairly disco, no? JUnit 4 takes a somewhat similar approach that requires a bit more legwork though:
- Create a generic test that takes no parameters
- Create a
staticfeeder method that returns aCollectiontype and decorate it with the@Parameterannotation - Create class members for the parameter types required in the generic method defined in step 1
- Create a constructor that takes these parameter types and correspondingly links them to the class members defined in step 3
- Specify the test case be run with the
Parameterizedclass via the@RunWithannotation
If I take the same code above and rework it to use JUnit 4 parameterizations, I first must create the generic test:
@Test
public void verifyHierarchies() throws Exception {
Hierarchy hier = HierarchyBuilder.buildHierarchy(clzz);
assertEquals("values were not equal",hier.getHierarchyClassNames(), names);
}
Second, I need to create a dynomite feeder method, which functions much like TestNG in that it requires an Object array with matching parameter types.
@Parameters
public static Collection hiearchyValues() {
return Arrays.asList(new Object[][] {
{Vector.class, new String[] { "java.util.AbstractList",
"java.util.AbstractCollection" } },
{String.class, new String[] {} } });
}
Note how this method is decorated with the @Parameter annotation, man. Next, because the parameters are of types Class and String[], I create two class members:
private Class clzz;
private String[] names;
Step 4 requires I create a constructor, which links values:
public HierarchyBuilderParameterTest(Class clzz, String[] names) {
this.clzz = clzz;
this.names = names;
}
Lastly, make sure you specify at the class level that this test be run with the Parameterized class like so:
@RunWith(Parameterized.class)
As you can see, JUnit makes you jump through a few more hoops, yet the fundamental requirements are quite similar to TestNG’s DataProvider feature. When push comes to shove, I still find TestNG’s semantics much simpler, but it’s nevertheless a disco feature to find in JUnit 4. Dig it?