JUnit 4 Tutorial 6 – Parameterized Test

In jUnit, you can use both @RunWith and @Parameter annotations to pass parameters into a Unit Test.

1. MathUtils – Parameterized Test

Review a simple add method.

MathUtils.java
package com.mkyong.match.utils;
 
public class MathUtils {
 
	public static int add(int a, int b) {
		return a + b;
	}
 
}

Here’s a jUnit test for above class, read the comments for self-explanatory.

MathUtilsTest.java
package com.mkyong.match.utils;
 
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
 
@RunWith(value = Parameterized.class)
public class MathUtilsTest {
 
	private int numberA;
	private int numberB;
	private int expected;
 
	//parameters pass via this constructor
	public MathUtilsTest(int numberA, int numberB, int expected) {
		this.numberA = numberA;
		this.numberB = numberB;
		this.expected = expected;
	}
 
	//Declares parameters here
	@Parameters(name = "{index}: add({0}+{1})={2}")
	public static Iterable<Object[]> data1() {
		return Arrays.asList(new Object[][] { 
			{ 1, 1, 2 }, 
			{ 2, 2, 4 }, 
			{ 8, 2, 10 }, 
			{ 4, 5, 9 } 
		});
	}
 
	@Test
	public void test_add() {	
		assertEquals(expected,MathUtils.add(numberA, numberB));
	}
 
}

What is {0}, {1} and {2}?
If parameter is “{ 3, 4, 7 }”, then {0} = 3, {1} = 4, {2} = 7. Refer to below output :

Output

junit-parameter-example-1

Figure : Eclipse jUnit Plugin Console

2. DomainUtils – Parameterized Test

Review a Domain name validator.

DomainUtils.java
package com.mkyong.regex.utils;
 
import java.util.regex.Pattern;
 
public class DomainUtils {
 
	private static Pattern pDomainName;
 
	private static final String DOMAIN_NAME_PATTERN = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}$";
 
	static {
		pDomainName = Pattern.compile(DOMAIN_NAME_PATTERN);
	}
 
	//is this a valid domain name?
	public static boolean isValidDomainName(String domainName) {
		return pDomainName.matcher(domainName).find();
	}
 
}

Here’s a jUnit test for above class.

DomainUtilsTest.java
package com.mkyong.regex.utils;
 
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
 
@RunWith(value = Parameterized.class)
public class DomainUtilsTest {
 
	private String domain;
	private boolean expected;
 
	public DomainUtilsTest(String domain, boolean expected) {
		this.domain = domain;
		this.expected = expected;
	}
 
	@Parameters(name= "{index}: isValid({0})={1}")
 	public static Iterable<Object[]> data() {
 		return Arrays.asList(new Object[][] { 
 		{ "google.com", true },
		{ "mkyong.com", true },
                { "-mkyong.com", false },
                { "mkyong-.com", false },
                { "3423kjk", false },
                { "mk#$kdo.com", false }
            }
 	);
     }
 
	@Test
	public void test_validDomains() {
		assertEquals(expected,DomainUtils.isValidDomainName(domain));
	}
 
}

Output

junit-parameter-example-2

Done.

Note
What I don’t like is you have to follow the “jUnit” way to declare the parameter providers, and pass it into the unit test via constructor. If compare with TestNG, TestNG is more flexible in the way of passing the parameters into unit test, read this TestNG parameter test.

References

  1. Domain Name RegEx Example
  2. jUnit Parameterized JavaDoc
  3. TestNG Parameter Test
Tags :

About the Author

mkyong
Founder of Mkyong.com and HostingCompass.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

  • Pingback: water ionizer pay plan loans()

  • Pingback: parking()

  • Pingback: water ionizer()

  • Pingback: water ionizer machine()

  • Pingback: stop parking()

  • Pingback: laan penge billigt()

  • Pingback: laan penge nu 18 aar()

  • Pingback: fue()

  • Pingback: check out DIRECTV channels()

  • Pingback: tvpackages.net()

  • Pingback: Website()

  • Pingback: online casinos()

  • Pingback: light gloves()

  • Pingback: petunia seeds()

  • Pingback: kagen water()

  • Pingback: alkaline water()

  • Pingback: best bottled water()

  • Pingback: water ionizer()

  • Pingback: watch tv show episodes()

  • Pingback: stream movies()

  • Pingback: watch movies online()

  • Pingback: watch tv show episodes()

  • Pingback: Blue Coaster33()

  • Pingback: Java Parameterized error | BlogoSfera()

  • Pingback: Java Parametrized error | BlogoSfera()

  • Pingback: Pruebas JUnit parametrizadas con cantidad variable de parámetros « También vine a estudiar()

  • Piotrek

    there is a simpler way. check zohhak.googlecode.com it lets you write:

    @TestWith({2,  true”, 
       “6,  false”,
       “19, true})
    public void testPrimeNumberValidator(int number, boolean isPrime) { 
       assertThat(}
  • Pingback: How to parameterize test in junit with example « selenium online training with expert()

  • Miguel Ping

    Nice post. BTW, it seems that is supporting any data time:

    	@Parameters
    	public static List&lt;Object[]&gt; data()
    	{
    		return Arrays.asList(new Object[][] { { DesiredCapabilities.chrome() }, { DesiredCapabilities.internetExplorer() } });
    	}
  • tobi

    thanks very much.. this really helped me!

  • kapil

    Hi ,

    I want to know that how we can implement different assertion for each parameter in same test case.
    As the collection of object is passed to constructor of Class. for every test run i want to have different assertion but that is not possible in current example.
    Thanks in advance.

  • Pingback: Personal taste for test and quality toolbox « Don't Make the Same Mistake Twice()

  • Pingback: Organizing test in unit testing | PHP Developer Resource()

  • Ramesh Kadali

    Hi,
    Could you please help me out regarding below issue:
    First Test case failure is carried to other consecutive tests when I used Parameterized tests. How can I skip this error:

    Below is the snippet of the code:

    package com.ncr.travel.airline.tests.myCopy;
     
    import static org.junit.Assert.*;
     
    import java.util.Arrays;
    import java.util.List;
     
    import org.junit.AfterClass;
    import org.junit.Assert;
    import org.junit.BeforeClass;
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.rules.ErrorCollector;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Parameterized.Parameters;
     
    @RunWith(Parameterized.class)
    public class ServerBuilderTest {
           @Parameters
           public static List&lt;Object[]&gt; data() {
        	   Object[][] lc = new Object[3][1];
        		lc[0][0]=0;
        		lc[1][0]=1;
        		lc[2][0]=0;
                   return Arrays.asList(lc);
           }
     
           private int fInput;
           private int fExpected;
     
           public ServerBuilderTest(int input) {
               super();    
        	   fInput= input;
           }
           @Rule
       	public static ErrorCollector errCollect = new ErrorCollector();
       	@BeforeClass
    	public static void setUp() throws Exception {
       		System.out.println(&quot;test&quot;);
       	}
    	@AfterClass
    	public static void tearDown() throws Exception {
    		System.out.println(&quot;After Test&quot;);
    	}
     
           @Test
           public void test() {
        	   try{
                   Assert.assertEquals(0, fInput);
        	   }
        	   catch (Throwable t) {
        		   System.out.println(t);
        		   errCollect.addError(t);
        	   }
     
     
           }
    }
    • Dileep

      Just remove the try and catch construct in test method
      issue found in the above code is :

      1) junit4 doesn’t have (Not worked for me)

      @Rule
      public static ErrorCollector errCollect = new ErrorCollector();

      2) private int fExpected;
      an unnecessary variable
      3) Exception handling in the test case is not appreciated …
      good to use like below

      @Test(expected = XXXXXXException.class)
      	public void XXXXX() {
                 ---------------------------------------
                  --------------------------------
      	}
    • Neel

      Hello Ramesh,
      I think the issue is that you have ‘static’ declared in your @Rule.
      create error collector instance without the ‘static’ keyword and it should work fine in Junit 4.

      @Rule
      public ErrorCollector errColl = new ErrorCollector();
  • Manjunath

    Hi ,

    Am new to Junit Testing and getting Initialization error while running Test class . pls help in resolving it , Thanks in advance

    code :

    package com.source;

    import java.util.Arrays;
    import java.util.Collection;

    import static org.junit.Assert.*;

    import org.junit.After;
    import org.junit.AfterClass;
    import org.junit.Before;
    import org.junit.BeforeClass;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Parameterized.Parameters;

    @RunWith(Parameterized.class)
    public class ParameterizedAddclassTest {
    public int a[];
    public int expected;

    ParameterizedAddclassTest(int inputparameters[],int expected)
    {
    this.a=inputparameters;
    this.expected=expected;
    }
    @Parameterized.Parameters
    public static Collection parameterPassing()
    {
    return Arrays.asList(new Object[][]{ {new int[]{5,2,3},10} ,
    {new int[] {5,10,15},30}
    });
    }

    @Test
    public void TestaddClass()
    {
    Addclass add =new Addclass();
    int actual=add.addClass(a);
    System.out.println(actual);
    assertEquals(actual,expected);
    }

    }

    error :
    java.lang.AssertionError: expected: but was:
    at org.junit.Assert.fail(Assert.java:58)
    at org.junit.Assert.failNotEquals(Assert.java:259)
    at org.junit.Assert.assertEquals(Assert.java:80)
    at org.junit.Assert.assertEquals(Assert.java:88)
    at org.junit.runners.Parameterized$TestClassRunnerForParameters.getOnlyConstructor(Parameterized.java:100)
    at org.junit.runners.Parameterized$TestClassRunnerForParameters.(Parameterized.java:80)
    at org.junit.runners.Parameterized$RunAllParameterMethods.(Parameterized.java:115)
    at org.junit.runners.Parameterized.(Parameterized.java:140)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:27)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.(JUnit4TestReference.java:29)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestClassReference.(JUnit4TestClassReference.java:25)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:40)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:30)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

  • Pingback: La R&D pilotée par les tests avec TestNG | Blog Onyme()

  • Binod Pant

    I am trying to subclass a Junit class to be used a ‘harness’ for parameterizing tests. I Want to subsclass a class that looks like

    @RunWith(Parameterized.class)
    public class A {
    @Parameters
    public Collection data() {
    return overrideableMethod();
    }

    }

    Subclass

    public class B extends A {
    @Override
    public Object[] overrideableMethod() {
    // change list of parmeters
    }
    @Test a() {
    }
    }

    However, this seems not to be possible due to Java treating the @Parameters annotation.

    My main objective is to simplify subclasses so that they don’t have to use the @Parameters and @RunWith annotations, and automatically get benefit of some standard parameters built into the base class

    Any tips / ideas?

  • Harry

    How do you make it jdk 1.5 (or above) compliance? I’m getting: The expression of type List needs unchecked conversion to conform to Collection

    • mkyong

      I’m using jdk1.6, has no warning at the above code.

      May be you can explicit convert the List to collection by using the following code,
      @Parameters
      public static Collectiondata() {
      Object[][] data = new Object[][] { { 1 }, { 2 }, { 3 }, { 4 } };
      return (Collection) Arrays.asList(data);
      }

      Did you use tTestNG before? Personally i more prefer to use TestNG as my unit test framework.

      http://www.mkyong.com/unittest/junit-4-vs-testng-comparison/