Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use a JUnit Parameterized runner with a varargs constructor?

Tags:

java

junit

I wrote a mockup example to illustrate this without exposing anything confidential. It's a "dummy" example which does nothing, but the problem occurs in the test initialiser.

@RunWith(Parameterized.class)
public class ExampleParamTest
{
 int ordinal;
 List<String> strings;

 public ExampleParamTest(int ordinal, String... strings)
 {
  this.ordinal = ordinal;
  if (strings.length == 0)
  {
   this.strings = null;
  }
  else
  {
   this.strings = Arrays.asList(strings);
  }
 }

 @Parameters
 public static Collection<Object[]> data() {
  return Arrays.asList(new Object[][] {
    {0, "hello", "goodbye"},
    {1, "farewell"}
  });
 }

 @Test
 public void doTest() {
  Assert.assertTrue(true);
 }
}

Basically I have a test constructor which accepts multiple arguments for a local list variable and I want to populate this through an array initialiser. The test method will handle the local list variable correctly - I have removed this logic to simplify the test.

When I write this, my IDE has no complaints about syntax and the test class builds without any compile errors. However when I run it, I get:

doTest[0]:
java.lang.IllegalArgumentException: wrong number of arguments
  at java.lang.reflect.Constructor.newInstance(Unknown Source)
doTest[1]:
java.lang.IllegalArgumentException: argument type mismatch
  at java.lang.reflect.Constructor.newInstance(Unknown Source)

What exactly has gone wrong here, and how do I correctly use this pattern?

like image 939
Adam Burley Avatar asked Aug 16 '10 13:08

Adam Burley


1 Answers

Can't test it right now but I guess, if you invoke a method or a constructor with variable arguments, you have to invoke it with an array instead of a variable list of values.

If I'm right, then this should work:

@Parameters
 public static Collection<Object[]> data() {
  return Arrays.asList(new Object[][] {
    {0, new String[]{"hello", "goodbye"}},
    {1, new String[]{"farewell"}}
  });
 }

Some explanation

On source code level, we can write

test = ExampleParamTest(0, "one", "two");

The compiler will convert this to an array of Strings. JUnit uses the reflection and invocation API, and from this perspective, the constructors signature is

public ExampleParamTest(int i, String[] strings);

So to invoke the constructor - and that's what JUnit is doing internally - you have to pass an integer and a String array.

like image 113
Andreas Dolk Avatar answered Nov 12 '22 08:11

Andreas Dolk