Take heed of mixing JUnit 4?s Parameterized tests - No Fluff Just Stuff

Take heed of mixing JUnit 4?s Parameterized tests

Posted by: Paul Duvall on April 13, 2007

One of the most handy features of JUnit 4 is its ability to run parameterized tests, which essentially means you can create a generic test and run it multiple times with various test parameters. In previous versions of JUnit, if you wanted to simulate this same behavior, you’d have to either:

  • loop over a collection of values
    • which means if there was a failure, the loop wouldn’t terminate
  • write unique test cases for each test data combination
    • which could prove to be a lot of coding

With parameterized tests, you can create a highly flexible testing scenario in five easy steps:

  1. Create a generic test and decorate it with the @Test annotation
  2. Create a static feeder method that returns a Collection type and decorate it with the @Parameters annotation
  3. Create class members for the parameter types required in the generic method defined in Step 1
  4. Create a constructor that takes these parameter types and correspondingly links them to the class members defined in Step 3
  5. Specify the test case be run with the Parameterized class via the @RunWith annotation

For example, the following test defines a generic test dubbed verifyGoodZipCode that tests four different combinations of zip codes defined in the feeder method named regExValues. Note too, the use of the @Parameters annotation and the @RunWith(Parameterized.class) class level decoration.

@RunWith(Parameterized.class)
public class ParametricRegularExpressionTest {

 private String phrase;
 private boolean match;

 private static String zipRegEx = "^\d{5}([\-]\d{4})?$";
 private static Pattern pattern;

 public ParametricRegularExpressionTest(String phrase, boolean match) {
  super();
  this.phrase = phrase;
  this.match = match;
 }

 @Parameters
 public static Collection regExValues() {
  return Arrays.asList(new Object[][] {
   {"22101", true },
   {"221x1", false },
   {"22101-5150", true },
   {"221015150", false }});
 }

 @Test
 public void verifyGoodZipCode() throws Exception{
  Matcher mtcher = this.pattern.matcher(phrase);
  boolean isValid = mtcher.matches();
  assertEquals("Pattern did not validate zip code", isValid, match);
 }

 @BeforeClass
 public static void setUpBeforeClass() throws Exception {
  pattern = Pattern.compile(zipRegEx);
 }
}

The astute reader will notice a subtle pattern relating to parameterized classes in JUnit 4– because of the member variable mapping with constructors, it becomes obvious that JUnit creates a new instance of the enclosing class for each test run. So in the example above, four instances will be created and the test method will be run four times with unique values relating to the Collection defined in the feeder method.

What this essentially means is that if you put a non-parametric test case in a parameterized class, it will also be run as many times as JUnit creates a new instance of your parameterized class. This isn’t a terrible thing, but it isn’t exactly elegant either. Hence, if you create parameterized test classes with JUnit 4, it probably makes sense to keep non-parameterized tests out of them. Simply put those methods in another test class.

Oh yeah, by the way, TestNG’s parameterized test classes don’t display this behavior. A non-parameterized test in a parameterized class will only be executed once. Nevertheless, JUnit 4’s parameterized test classes are an excellent way to achieve a high degree of code confidence with fewer test methods.

Paul Duvall

About Paul Duvall

Paul M. Duvall is the CEO of Stelligent, a consulting firm that helps clients create production-ready software every day. He has worked in virtually every role on software projects: developer, project manager, architect and tester. He's been a featured speaker at many leading software conferences. He is the principal author of Continuous Integration: Improving Software Quality and Reducing Risk (Addison-Wesley, 2007; Jolt 2008 Award Winner). He contributed to the UML 2 Toolkit (Wiley, 2003), authors a series for IBM developerWorks called Automation for the people and authored a chapter in the No Fluff Just Stuff Anthology: The 2007 Edition (Pragmatic Programmers, 2007). He is passionate about automating software development and release processes. He actively blogs on IntegrateButton.com

Why Attend the NFJS Tour?

  • » Cutting-Edge Technologies
  • » Agile Practices
  • » Peer Exchange

Current Topics:

  • Languages on the JVM: Scala, Groovy, Clojure
  • Enterprise Java
  • Core Java, Java 8
  • Agility
  • Testing: Geb, Spock, Easyb
  • REST
  • NoSQL: MongoDB, Cassandra
  • Hadoop
  • Spring 4
  • Cloud
  • Automation Tools: Gradle, Git, Jenkins, Sonar
  • HTML5, CSS3, AngularJS, jQuery, Usability
  • Mobile Apps - iPhone and Android
  • More...
Learn More »