5

I would like to make a data-driven parametrized method in JUnit.

The examples that I see, parametrize the whole class.

E.g.

@RunWith(Parameterized.class)
public class PrimeNumberCheckerTest {

However, I would like to parametrize a single test method, not the whole class.

In TestNG, something like that seems to look like this:

@DataProvider(name = "test1")
public static Object[][] primeNumbers() {
   return new Object[][] {{2, true}, {6, false}, {19, true}, {22, false}, {23, true}};
}

// This test will run 4 times since we have 5 parameters defined
@Test(dataProvider = "test1")
public void testPrimeNumberChecker(Integer inputNumber, Boolean expectedResult) {
   System.out.println(inputNumber + " " + expectedResult);
   Assert.assertEquals(expectedResult,
   primeNumberChecker.validate(inputNumber));
}

Is such a thing possible in JUnit?

EDIT:

  1. The most elegant/DRY way would be to have a single method-level annotation - which is what I'm hoping for.

  2. I've found a library:

https://github.com/Pragmatists/junitparams

Example:

@RunWith(JUnitParamsRunner.class)
public class PersonTest {

  @Test
  @Parameters({"17, false", 
               "22, true" })
  public void personIsAdult(int age, boolean valid) throws Exception {
    assertThat(new Person(age).isAdult(), is(valid));
  }

}

The question still remains - is there something like that built into JUnit?

If not, then what is the closest built-in thing that would require the least amount of boiler-plate code or class-level contortions?

KarolDepka
  • 8,318
  • 10
  • 45
  • 58

2 Answers2

4

You can use @RunWith(Suite.class) and @Suite.SuiteClasses to turn your outer class into a suite, and then have nested classes inside (defining the "sub-test-classes" of the suite), each with their own runner.

@RunWith(Suite.class)
@Suite.SuiteClasses({MyFooTest.Individual.class, MyFooTest.WithParams.class})
public class MyFooTest {

  @RunWith(Parameterized.class)
  public static class WithParams {
    @Parameterized.Parameters
    public static Collection<Object[]> primeNumbers() {
      ...
    }
    @Test
    public void testPrimeNumberChecker() {
      ...
    }
    ...
  }

  public static class Individual {
    @Test
    public void someOneOffTest() {
      ...
    }
    ...
  }
}
yshavit
  • 42,327
  • 7
  • 87
  • 124
  • Thanks. This seems like a lot of overhead though. I was hoping for a single method-level annotation... Like in here - https://github.com/Pragmatists/junitparams . – KarolDepka Jan 08 '17 at 21:21
  • I've added those remarks into the "EDIT" section in my question as well. – KarolDepka Jan 08 '17 at 21:28
  • 1
    I don't know offhand, but you _may_ be able to use the outer class itself as one of the subsuites: `@Suite.SuiteClasses({MyFooTest.class, MyFooTest.WithParams.class})`. That way only your parameterized tests need their own class, which at least cuts down on some of the overhead. It does feel like a lot, I agree. As far as I know, this is the best way with junit. – yshavit Jan 09 '17 at 03:09
2

TestNG is supposed to be able to run JUnit tests: so, you can use TestNG as runner and having old tests in JUnit + new/parameterized tests in TestNG.

From the documentation:

TestNG can run JUnit 3 and JUnit 4 tests. All you need to do is put the JUnit jar file on the classpath, specify your JUnit test classes in the testng.classNames property and set the testng.junit property to true:

<test name="Test1" junit="true">
  <classes>
    <!-- ... -->
juherr
  • 5,640
  • 1
  • 21
  • 63
  • Thanks. Could you provide some link which explains this (ideally, with a quote) ? Ideally pointing to real-world limitations of that setup. Then I will upvote :). – KarolDepka Jan 09 '17 at 17:08
  • @KarolDepka Quote added, hope it will be enough – juherr Jan 10 '17 at 09:35