Code & Iron

Over and Over: Parameterized Testing in JUnit

So you love creating meaningful test cases, right? You get jazzed about your software working, and even better; you can prove it. But here’s the issue: many of the test cases in that 100 page “test plan” are data-driven. You find yourself creating the same test method over and over again with the only difference being the in’s and out’s. You don’t repeat yourself in the src/main directory, so why should it be okay in the src/test directory?

Don’t get W.E.T., D.R.Y. it up! No, there’s no need to create a .properties file of your data set to be read into the tests. Don’t you dare create a custom XML schema, XML files and parser. Stop right there! I see you over there creating your own XML-based testing suite. You aren’t the first person to try this… it’s been done, and done well!

The custom Parameterized runner in JUnit 4 is ideal for when you want to execute the same test method many times with varying inputs and varying expected outputs. Below I’ve set up a basic test class that confirms the operation of a web page that will sum any two values. It uses the Selenium Webdriver page objects pattern, but that’s a discussion for another day.

@RunWith(Parameterized.class)
public class ValidInputValueTests {
	
	private String inputValue1;
	private String inputValue2;	
	
	public ValidInputValueTests(String inputValue1, String inputValue2, String outputValue){		
		this.inputValue1 = inputValue1;
		this.inputValue2 = inputValue2;
                this.outputValue = outputValue;
	}	
	
	@Parameters
	public static Collection<Object&#91;&#93;> generateData() {
		return Arrays.asList(new Object[][] {				 
				 {"10.00", "", "10.00"},
				 {"10.00", "10.00", "20.00"},
				 {"", "10.00", "10.00"}
				 });
	}
	
	@Test
	public void TC2_4_2PerformThisTestForParameters(){		
		InputPage inputPage = certainNextPage.enterValuesAndClickNext(inputValue1, inputValue2);
		FinalPage finalPage = inputPage.enterStandardInfoAndSubmit();
		
		Assert.assertEquals("Actual value does not match expected value on finalPage", outputValue, finalPage.getResult());
	}
}

Instead I’ll discuss each part in detail as pertains to JUnit Parameterized tests. First off, import and add the annotation to RunWith the Parameterized custom runner from the JUnit 4 API. This is how JUnit knows to scan the test class for the @Parameters within it.

@RunWith(Parameterized.class)
public class ValidInputValueTests {

Next, the class must have a publicly visible constructor with the same number of arguments as parameters.

	public ValidInputValueTests(String inputValue1, String inputValue2, String outputValue){		
		this.inputValue1 = inputValue1;
		this.inputValue2 = inputValue2;
                this.outputValue = outputValue;
	}

Then tell JUnit where your parameters are residing by annotating a static method called generateData that returns a collection of object arrays (don’t ask, this is a weird quirk of the Parameterized class IMO). These will be injected into the test class constructor by Parameterized. To date I’ve only used Java standard types and primitives (Strings, boolean, etc.) as parameters and haven’t experimented with passing custom objects.

	@Parameters
	public static Collection<Object&#91;&#93;> generateData() {
		return Arrays.asList(new Object[][] {				 
				 {"10.00", ""},
				 {"10.00", "10.00"},
				 {"", "10.00"}
				 });
	}

Now let’s set up our test method. Note that you could put as many methods in this test class as you want. They will all be executed in turn with the set of parameters above, making the Parameterized runner VERY powerful, talking N X M powerful. It effectively generates a test method instance for every result in the cross product of parameter sets and test methods.

	@Test
	public void TC2_4_2PerformThisTestForParameters(){	
		...
		InputPage inputPage = certainNextPage.enterValuesAndClickNext(inputValue1, inputValue2);
		FinalPage finalPage = inputPage.enterStandardInfoAndSubmit();
		
		Assert.assertEquals("Actual value does not match expected value on finalPage", outputValue, finalPage.getResult());
	}

Note that in the above test method, we have access to our inputValue 1 and 2, and our output value, trusting in Parameterized.class to populate these variables with our test data.

So why not create some data driven tests for your system today! Super simple, super quick, super powerful, god I love JUnit.

Take care,
Matt

  Posted by Matt Holtom in Blog, Uncategorised on February 1, 2012

Leave a Reply

Your email address will not be published. Required fields are marked *