JUnit’s parameterized test cases

I like JUnit. I really do. It has really cool features that make my life easier when it comes to testing. I like how I can document my production code with a set of tests. I also like the clear way of separation of the test cases; that each of them have a unique, descriptive name; that they all represent a well understandable use case.

However, I hate, yes it’s true, I HATE this particular feature JUnit offers, namely parameterized test cases. Parameterized test cases contain a set of values with which the same method will be tested. Let’s see a very basic example. Consider a very simple Rectangle class:

public class Rectangle {

	private final int width;
	private final int length;

	public Rectangle(int width, int length) {
		this.width = width;
		this.length = length;
	}

	public int getArea() {
		return length*width;
	}
}

Now, suppose we want to test the logic that computes the area. So we create a parameterized test file, like this:

@RunWith(Parameterized.class)
public class ParameterizedRectangleTest {

	Rectangle rectangle;
	private final int width;
	private final int length;

	public ParameterizedRectangleTest(int width, int lenght) {
		this.width= width;
		this.lenght = lenght;
		rectangle = new Rectangle(width, lenght);
	}

	@Parameters
	public static List<Object[]> parameters() {
		return Arrays.asList(new Object[][] { { 1, 2 }, { 2, 2 }, { 5, 7 },
				{ 10, 2 } });
	}

	@Test
	public void testRectangleArea() throws Exception {
		Assert.assertEquals(height * width, rectangle.getArea());
	}
}

Let’s see what are the main components of our test file:

  • @RunWith(Parameterized.class) : by default JUnit tests run with the JUnit test runner. However, if you’re using a mock framework (JMock for example), than you might need to run with the corresponding runner. Parameterized tests run with the Parameterized runner; by stating this you will let JUnit know that you’re supplying test data through a data provider method.
  • @Parameters: this is the method that will provide the test data. It has to be both public and static. It’s return type is a Collection. Usually it does not do anything, just returns a set of values, input data.
  • Constructor: not very usual in case of JUnit tests. Try not to use one, you’ll instantly get an IllegalArgumentException. Here you are able to access the current test data, build objects, just the usual constructor stuff.

And mainly that’s it. Pretty simple, after all. When you run the tests, JUnit will test the getArea() method with each and every piece of the test data described in the parameters() method.

Although it looks simple, I do have some arguments why these tests should not appear as unit tests:

  1. In a larger project, chances are quite high that you’re using a mocking framework. Common things required by the mocker are usually grouped together into fixture files (along with the @RunWith annotation). If you have different runners, you have to specify every time which one you are using, and this makes test files more noisy.
  2. If you tried it out, you know by now that the results will be something like this: well, these are not very self-documenting names. There’s no way of knowing which are normal cases, special cases, edge cases, error cases etc.
  3. If you break one of these test cases in a large legacy system, you are going to have a bad time finding what went wrong.
  4. Ever tried to figure out what a class’ responsability was, just by looking at its test cases? You can’t do it here, as you have only one test method.
  5. Usually we do not write test cases just to have more test cases. We write test cases to create/validate behavior. In this context this bunch of test data seems useless, as they all test the very same behavior.
  6. It’s hard to get. Someone who has never seen such test cases may be confused about the unusual layout of the class.
  7. In every case I ran into such tests the actual test method was long, full of asserts and even full of other stuff, like loops, try-catches etc.

Anyway, I’m open to new ideas. If you’ve ever used parameterized test cases successfully (and ended up with clean and understandable code), feel free to share.

Advertisements

Author: tamasgyorfi

Senior software engineer, certified enterprise architect and certified Scrum master. Feel free to connect on Twitter: @tamasgyorfi

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s