2

I'm looking for the most readable way to share tests of different implementations of an interface.

The most popular, but rather old question on this subject was - Writing a single unit test for multiple implementations of an interface.

To the question above, 2 main and different answers were given -

  1. Parameterized tests.
  2. Test inheritance.

I'm not satisfied with both answers.

  1. Parameterized test - the answer doesn't include a code example of how to parameterize each subclass. Also, I personally have a hard time with parameterized test and I find the API not intuitive at all.

  2. I always fear inheritance overusing, and I'm not sure if a test inheritance is a good practice.

I wonder what is the best answer to this question in 2018.

Paz
  • 1,023
  • 4
  • 14
  • 31

2 Answers2

1

Parameterizing your test still seems like the textbook solution to such usecases. JUnit Jupiter's syntax does make it a tad more elegant, though. The API is quite clearer, IMHO (the tests have arguments, and an annotation shows where they come from):

public class ListTest {

    public static Stream<List<String>> lists() {
        return Stream.of(new ArrayList<>(), new LinkedList<>());
    }

    @ParameterizedTest
    @MethodSource("lists")
    public void testAdd(List<String> list) {
        list.add("xyz");
        assertEquals(1, list.size());
        assertFalse(list.isEmpty());
        assertEquals("xyz", list.get(0));
    }
}
Mureinik
  • 297,002
  • 52
  • 306
  • 350
0

Probably not the most Java-like, but you can follow a table-driven test format. Using an local class, to keep test most readable, and keep context as close to real test as possible.

Note: this is very similar to underlying high-level approach of @RunWith(Parameterized.class)

// Assuming Animal interface has a `public boolean canDance()`

@Test
public void TestAnimalCanDance() {
    class Tester {
        String errMsgFmt = "%s failed the test";
        boolean expected;
        Animal animal;
        public Tester(boolean expected, Animal animal) {
            this.expected = expected;
            this.animal = animal;
        }
    }

    Tester dog = new Tester(true, new Dog());
    Tester cat = new Tester(false, new Cat());
    Tester monkey = new Tester(false, new Monkey());
    Tester[] tests = Arrays.asList(dog, cat, monkey);

    for (Tester t: tests) {
        boolean actual = t.canDance();
        assertTrue(actual == t.expected);
    }
}
Debosmit Ray
  • 5,228
  • 2
  • 27
  • 43