JUnit - 分享不同实现的测试

JUnit - Share Tests Of Different Implementations

我正在寻找最易读的方式来共享接口不同实现的测试。

关于这个主题的最受欢迎但相当古老的问题是 - Writing a single unit test for multiple implementations of an interface.

针对上述问题,给出了 2 个主要和不同的答案 -

  1. 参数化测试。
  2. 测试继承。

我对这两个答案都不满意。

  1. 参数化测试 - 答案不包括如何对每个子类进行参数化的代码示例。另外,我个人很难进行参数化测试,我发现 API 一点也不直观。

  2. 我总是害怕过度使用继承,而且我不确定测试继承是否是一个好的做法。

想知道2018年这个问题的最佳答案是什么

可能不是最像 Java 的,但您可以遵循 table 驱动的测试格式。使用本地 class,以保持测试的可读性,并使上下文尽可能接近真实测试。

注意:这与 @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);
    }
}

参数化您的测试似乎仍然是此类用例的教科书解决方案。 JUnit Jupiter's syntax 确实让它更优雅了一点,不过。 API 更清楚,恕我直言(测试有参数,注释显示它们的来源):

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));
    }
}