Tuesday, December 21, 2010

Data Providers - good or bad?

At work we use TestNG. It has the ability to do DataProviders for your unit tests :
 TestNG DataProviders
JUnit 4 also allows you to do DataProviders.

I don't think DataProviders play very well with the notion of "self documenting code". I take it as self documenting code is not only the absence of JavaDoc and comments, not only variable and method names that make sense, but also unit tests that help you understand how the unit of code behaves under different circumstances.

As a developer on a new project which test would help you better figure out what the code does?

This:

@DataProvider(name = "greenCardData")
public Object[][] getGreenCardData() {
 return new Object[][] {
   {"Boyko", false}, {"Vladimir", true},{ "Borat", true},{ "Ricky Bobby", true} 
};
}
@Test(dataProvider = "greenCardData")
public void testHasGreenCard(String name, boolean expectedValue) {
   assertEquals(expectedValue, immimgrationServiceUnderTest.hasGreenCard(name));
}


or this:
@Test
public void ensureHasGreenCardReturnsFalseWhenNameIsBoyko() {
      assertFalse( immigrationServiceUnderTest.hasGreenCard("Boyko");
}

@Test
public void ensureHasGreenCardReturnsTrueWhenNameIsNotBoyko() {
      assertTrue( immigrationServiceUnderTest.hasGreenCard("John Madden");
}

In my opinion, if I am a new developer on a team and I happen to not have worked with data providers before, it would be easier and faster to pick up the domain specifics following the wordier, dataProviderless version.

On the flip side though, if I need to test a method whose args could have many possible values and return many possible values, the data provider way becomes more useful.

@DataProvider(name = "additionData")
public Object[][] getAdditionData() {
 return new Object[][] {
   {2, 2, 4}, {3, 3, 6},{ 5, 6, 11},{ 8, 10, 18}, {40, 60, 100} 
};
}
@Test(dataProvider = "additionData")
public void testAddNumbers(int number1, int number2, int result) {
   assertEquals(result, additionServiceUnderTest.addNumbers(number1, number2));
}