This file describes how to automate unit tests using parameters for data values.

Why AuctionTest Needs a Parameter

You must run your unit tests using the 7 different variations of Auction code, so you need to call setAuctionType(n) before testing the Auction.

The most convenient place to do this is in a setUp method, like this:

public class AuctionTest {
	// an Auction attribute for tests to use (test fixture)
	private Auction auction;

	// initialize the Auction before each test
	@Before
	public void setUp() {
		auction = new Auction("Core Java");
		auction.setAuctionType(1);
	}

After running all tests you need to change auctionType to 2 and run again, then change auctionType to 3 and run again, etc.

If you change any of your tests, you need to repeat the whole process!

You can automate this work using Parameterized Tests.

How to Create Parameterized Tests

JUnit can run the same set of test methods multiple times using different values of some variables. This is called parameterized unit tests.

You need to do 3 things in your test class.

1. Add @RunWith(Parameterized.class) to Class

import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class AuctionTest {
	// your unit tests
}

2. Define a public static Method that Returns Values for Parameter(s)

This method returns a Collection, where each element in the collection contains one set of values to use in tests. You can have more than one parameter, so the values are stored in an array of Object.

In our tests, we only need one parameter (the auctionType), so the arrays just contain a single element:

@Parameterized.Parameters(name="Tests for auctionType={0}")
public static Collection<Object[]> getParameters() {
	// a 2-dimensional array
	// each ROW in the array is one set of parameter values
	Object[][] data = {
		{1},  // first value of parameter
		{2},  // second value of parameter
		{3},  // third value of parameter
		{4}   // etc.
	};
	return java.util.Arrays.asList(data);
}

You can name this method anything you like. The import thing is that it is public static Colection<Object[]>.

3. Receive Parameter Values to Attributes Used in Your Tests

The last (and most important) step is to assign the parameter values to some attributes in your code, then use those attributes in setUp.

3.1 Assign Values Using a Constructor

You can write a constructor with parameters, and JUnit will call the constructor with your parameterized data.

/**
 * Assign parameter values using constructor.
 */
@RunWith(Paramaterized.class)
public class AuctionTest {
	// an Auction used in the tests
	private Auction auction;
	// the auctionType, which is used in setUp
	public int auctionType;

	// initialize Auction before each test
	@Before
	public void setUp() {
		auction = new Auction("Core Java");
		auction.setAuctionType(this.auctionType);
		//TODO temporarly add a print statement to verify its working?
	}

	// Constructor to receive parameter values
	public AuctionTest(int auctiontype) {
		this.auctionType = auctiontype;
	}

3.2 Assign Parameter Values Directly to Attributes

Junit can directly set the values of public attributes (must be public) so you don’t need a constuctor.
Annotate attributes you want to set using Parameterized.Parameter(n). The attribute must be public.

/**
 * Assign parameter values directly to public attributes (no constructor)
 */
@RunWith(Paramaterized.class)
public class AuctionTest {
	// an Auction used in the tests
	private Auction auction;
	// the auctionType, which is used in setUp
	@Parameterized.Parameter(0)
	public int auctionType;

	// initialize Auction before each test
	@Before
	public void setUp() {
		auction = new Auction("Core Java");
		auction.setAuctionType(this.auctionType);
	}

Running the Tests

JUnit will run all your tests for each row of data in the collection returned by the @Parameterized.Parameters method. It prints a message using the name you specify in the annotation. For example:

[Tests for auctionType=1]
  testNewAuctionState
  testCanBid
  testWinnerAndBestBid
[Tests for auctionType=2]
  testNewAuctionState
  testCanBid
  testWinnerAndBestBid
[Tests for auctionType=3]
  testNewAuctionState
  testCanBid
  testWinnerAndBestBid
 ...

More Than One Parameter?

You can have more than one parameter for parameterized tests.

The Auction has a minimum bidding increment. Suppose you want to test the Auction using a bidding increment of 1 and 20. You can make this be another parameter for the tests:

/**
 * Inject parameter values directly to public attributes (no constructor)
 */
@RunWith(Paramaterized.class)
public class AuctionTest {
	private Auction auction;
	// the auctionType, which is used in setUp
	@Parameterized.Parameter(0)
	public int auctionType;
	// the minimum bidding increment
	@Parameterized.Parameter(1)
	public int minIncrement;

	// initial Auction before each test
	@Before
	public void setUp() {
		auction = new Auction("Core Java", minIncrement);
		auction.setAuctionType(this.auctionType);
	}

	@Parameterized.Parameters(name="Tests for auctionType={0} minIncrement={1}")
	public static Collection<Object[]> getParameters() {
		// each ROW in the array is one set of parameter values
		Object[][] data = {
			//{auction type, min increment}
			{1, 1},
			{1, 20},
			{2, 1},
			{2, 20},
			{3, 1},
			{3, 20},
            // etc.
     	};
		return java.util.Arrays.asList(data);
	}

Resources

  • DZone Article shows how to assign values of parameters directly to attributes in your test class.

  • TutorialsPoint has example where parameter values are passed to a constructor in your test class. Normally, test classes don’t need a constructor but here its useful.