SOFTWARE ENGINEERING blog & .lessons_learned
manuel aldana
Manuel Aldana

April 19th, 2009 · No Comments

Parameterized test-methods with TestNG

TestNG offers many great features and is definitely more capable as JUnit to build a strong automated Test-Suite. When writing test-cases one important factor is the handling of test-data. With JUnit it is cumbersome to feed different test-data to the same test-code. TestNG solves this much better.

Let’s look at a very simple example. When trying to test an exception with JUnit 4 with different test-data I would need to write something like:

class MyTest{

  @Test
  public void throw_exception_if_wrong_input()
  {
    try
    {
      new Foo(“test-data1″);
      fail();
    }catch(IllegalArgumentException iae){}
   
    try
    {
      new Foo(“test-data2″);
      fail();
    }catch(IllegalArgumentException iae){}
   
    try
    {
      new Foo(“test-data3″);
      fail();
    }catch(IllegalArgumentException iae){}   
  }

}

This code has essential problems:

  1. Because I want to avoid to write two more test-methods (essentialy the same production code is triggered), I am putting three test-cases into one test-method, which is bad practice. This is because test cases aren’t using the tearDown and setUp facilities and cannot guarantee isolation. That is also the reason that I could not use the excpectedException parameter inside the JUnit 4 @Test annotation. Alternative is to really use three test-methods, but code readability then suffers.
  2. Even though above example is very simplified (only new Foo() is called) the test-code is not expressive. Surely you could improve this by extracting method and giving a good name. But still it is a bit blurry, why we do so and that it is just for using different test-data.

TestNG parameterized test-methods

TestNG does it better and builds the “test-case differs only in test-data” situation into its framework. This is done by building a DataProvider and passing parameters to the test-method. This way code gets more expressive and each different test-data set is executed as an isolated test-case also. Here an example of the TestNG version of above test-cases (I followed the code centric way, you can also configure your DataProvider through an XML file):

class MyTest{

  @DataProvider(name = “wrong_input”)
  public Object[][] createData()
  {
    //2 dimensions
    // x: data-set for one test-case
    // y: set of parameters (test-method can contain multiple parameters)
    return new Object[][]{
        {“test-data-1″},
        {“test-data-2″},
        {“test-data-3″}
    };
 }

 @Test(expectedExceptions = IllegalArgumentException.class,
            dataProvider = “wrong_input”)
 public void throw_exception_if_bad_input(String input)
 {
   new Foo(input)
 }
 
}

Tags: Continous Integration · Software Engineering

0 responses

    You must log in to post a comment.