19

I have a JUnit 4 test that loops through an array of test data:

public @Test void testAll() {

    final Object[][] sets = new Object[][] {
            // SET                              TYPE VALUE

            // --- valid sets

            // groups
            x(s(A,1, B,1, C,1),                 G),
            x(s(A,4, B,4, D,4),                 G),
            x(s(A,8, B,8, D,8, C,8),            G),
            x(s(J,J, B,4, D,4),                 G,  4*3),
            x(s(A,9, J,J, D,9),                 G,  9*3),
            x(s(A,2, B,2, C,2),                 G),
            x(s(A,4, B,4, J,J),                 G,  4*3),
            x(s(A,4, B,4, C,4, D,4),            G),

            // runs
            x(s(A,1, A,2, A,3),                 R),
            x(s(B,8, B,9, B,10),                R),
            x(s(J,J, C,2, C,3),                 R,  6),
            x(s(D,8, D,9, J,J, D,11),           R,  38),
            x(s(D,8, D,9, J,J, J,J),            R,  38),

            // sames
            x(s(A,1, A,1),                      S),
            x(s(B,4, B,4, B,4),                 S),
            x(s(C,8, C,8),                      S),
            x(s(D,3, D,3),                      S),

            // doubt-cases, assume group (TODO: verify this is correct)
            x(s(J,J, J,J, D,4),                 G,  4*3),
            x(s(A,7, J,J, J,J),                 G,  7*3),
            x(s(J,J, D,9, J,J),                 G,  9*3),
            x(s(J,J, J,J, J,J),                 G,  1),

            // --- invalid sets
            x(s(B,1, A,2, A,3),                 I), // not same colour
            x(s(D,11, D,12, J,J, J,J),          I), // last joker is 14
            x(s(B,1, B,1, A,1),                 I), // duplicate B1
            x(s(A,1, A,2, A,3, A,5),            I), // gap A4
            x(s(J,J, A,1, J,J, B,1, C,1),       I), // one J replaces D1, then nothing left to replace
            x(s(A,1, A,2),                      I), // short
            x(s(B,1),                           I), // shorter
            x(s(A,5, A,6),                      I), // short
    };

    for (Object[] o : sets) {

        TileSet s = (TileSet) o[0];
        Type t = (Type) o[1];
        int v = (Integer) o[2];

        System.out.println(s);

        assertEquals(t, s.getType());
        assertEquals(v, s.getValue());

        // test isValid, though it's Too Simple To Break(R)
        if (t == Type.INVALID) assertFalse(s.isValid());
        else assertTrue(s.isValid());
    }

}

Because it's all in one test method, the whole test stops as soon as one element in the array fails. Is there a way around that, without making a method for each test item? Maybe something with reflection?

Bart van Heukelom
  • 43,244
  • 59
  • 186
  • 301
  • 1
    If you need it to continue through assert failures, how about building up a list of elements that fail, as you're looping, then asserting that the list is empty after the loop? If it's not empty, print out the list of failures. – wkl Nov 22 '10 at 16:58
  • @birryree how would you do this? wouldn't the looping stop once an element fails? I'm a beginner btw. – papercuts Mar 05 '13 at 10:08

3 Answers3

22

Use JUnit 4's parameterized tests. They are a perfect fit for this type of problem, although the documentation is quite lacking.

Here are a few other samples on how to use them.:

Vadik Sirekanyan
  • 3,332
  • 1
  • 22
  • 29
matt b
  • 138,234
  • 66
  • 282
  • 345
  • 1
    This is exactly what I need. One thing though, is there a way to show the toString() of the test data in the test results? It's inconvenient to have to keep looking them up by array index. – Bart van Heukelom Nov 22 '10 at 21:28
  • you might want to look into either subclassing the Parameterized runner or providing your own implementation and overriding the `getName()` method inside the inner class `TestClassRunnerForParameters` – matt b Nov 22 '10 at 21:41
  • Is something like this possible on the (@Test) method level? I want to repeat only some methods in the class and I already use @RunWith for something else. – David Balažic Jun 10 '16 at 20:36
  • 1
    Is there a way to do this without relying on static Parameters? I'm using some random data generation for my parameters... – Daniel Patrick Jul 28 '16 at 18:05
5

catch AssertionError and add the caught error to the errors list, at the end check the list to be empty raise a compound AssertionError if not.

khachik
  • 28,112
  • 9
  • 59
  • 94
1

Parameterized Tests in JUnit 5 have got easier with a better syntax, I think. You can read about it here. One of the options is to declare a method to provide the list of arguments to test, such as below:

// Given
private static Stream<Arguments> shouldReturnExpectedResultWhenGivenRightInput() {
   return Stream.of(
       Arguments.of(3, "Fizz"),
       Arguments.of(5, "Buzz"),
       Arguments.of(8, "8"),
       Arguments.of(15, "FizzBuzz"),
       Arguments.of(19, "19"),
       Arguments.of(30, "FizzBuzz"),
       Arguments.of(40, "Buzz"),
       Arguments.of(45, "FizzBuzz")
   );
}
@ParameterizedTest
@MethodSource
void shouldReturnExpectedResultWhenGivenRightInput(Integer input, String expected) {
   // When
   val result = library.processInput(input); 
   // Then
   assertEquals(expected, result);
}

// Given
private static Stream<Arguments> shouldNotReturnExpectedResultWhenGivenWrongInput() {
    return Stream.of(
        Arguments.of(3, "Buzz"),
        Arguments.of(5, "Fizz"),
        Arguments.of(8, "Buzz"),
        Arguments.of(15, "15"),
        Arguments.of(19, "Fizz")
    );
}
@ParameterizedTest
@MethodSource
void shouldNotReturnExpectedResultWhenGivenWrongInput(Integer input, String unexpected) {
    // When
    val result = library.processInput(input); 
    // Then
    assertNotEquals(unexpected, result);
}
dbaltor
  • 2,737
  • 3
  • 24
  • 36