Java 测试实现相同接口的类的最佳方法

Java 测试实现相同接口的类的最佳方法,java,junit,junit4,Java,Junit,Junit4,例如,我有几个类实现了List接口。如何测试它们——它们是否正确地实现了方法 现在我只看到一种方法: public class MyListImplementationsTest { private Collection<List<Integer>> listImplementations; @BeforeClass public static void setUp() throws Exception { listImpleme

例如,我有几个类实现了
List
接口。如何测试它们——它们是否正确地实现了方法

现在我只看到一种方法:

public class MyListImplementationsTest {
    private Collection<List<Integer>> listImplementations;

    @BeforeClass
    public static void setUp() throws Exception {
        listImplementations = Arrays.asList(
            new QuickList<Integer>(), new EfficientMemoryList<Integer>()
        );
    }

    @Test
    public void testIsEmptyAfterCreationEmptyList() {
        // Use forEachList(handler) in order to not iterate
        // the lists manually every time.
        // May be there is no need to do so,
        // because using <<for (item : items)>> instead of
        // iterating using index prevents from OutOfBounds errors
        forEachList(new OnEachListHandler<Integer>() {
            @Override
            public void onEach(List<Integer> list) {
                assertTrue(list.isEmpty());
            }
        });
    }

    private <T> void forEachList(OnEachListHandler<T> handler) {
        for (List<T> each : listImplementations) {
            handler.onEach(each);
        }
    }

    private static interface OnEachListHandler<T> {
        void onEach(List<T> each);
    }
}
公共类MyListImplementsTest{
私有收集列表实现;
@课前
public static void setUp()引发异常{
listImplementations=Arrays.asList(
新建QuickList(),新建EfficientMemoryList()
);
}
@试验
CreationEmptyList()之后的公共无效证明{
//使用forEachList(处理程序)以避免迭代
//每次都手动创建列表。
//可能没有必要这样做,
//因为使用而不是
//使用索引进行迭代可防止边界外错误
forEachList(新的OnEachListHandler(){
@凌驾
公共无效onEach(列表){
assertTrue(list.isEmpty());
}
});
}
私有void forEachList(OnEachListHandler){
对于(列出每个:列表实现){
handler.onEach(每个);
}
}
私有静态接口OnEachListHandler{
void onEach(每个列表);
}
}
但在我看来,在每次测试中迭代列表是很复杂的


JUnit4
中是否有更优雅的方法来测试实现相同接口的类?

您可以创建一个基本测试,它可以测试任何类型的
List
以及一个创建这样一个列表的抽象方法

然后根据列表类型实现一个测试,该测试扩展了基本测试。JUnit将从基类以及您在扩展中定义的任何类运行测试用例

abstract class AbstractListTest<T> {
    protected abstract List<T> createList();

    @Test
    public void testIsEmpty() {
        List<T> list = createList();
        assertTrue(list.isEmpty());
    }

    ...more tests...
}

class QuickListTest extends AbstractListTest<QuickList> {
    protected QuickList createList() {
        return new QuickList();
    }
}
抽象类AbstractListTest{
受保护的抽象列表createList();
@试验
公开无效证明(){
List=createList();
assertTrue(list.isEmpty());
}
…更多测试。。。
}
类QuickListTest扩展了AbstractListTest{
受保护的QuickList createList(){
返回新的快速列表();
}
}
JUnit不会运行抽象基类,但会看到继承的测试并运行所有测试。您还可以将新测试添加到
QuickListTest
或重写基类中的测试


基本上,JUnit将使用该类,从整个继承树中查找所有公共的代码>代码>测试> /代码>方法。

< P>我将考虑将不同列表实现的测试分解到它们各自的测试用例中,使它们独立地通过或失败。p> 以您的
.isEmpty()
为例,如果
快速列表.isEmpty()
效率记忆列表.isEmpty()
有不同的实现,即
空的概念有不同的含义,那么独立测试它们是有意义的。当前,如果1个列表实现失败,则您的
testIsEmptyAfterCreationEmptyList
将失败,但其他列表都已通过

否则,如果<代码> iSuthType()/<代码>和<代码>高效内存> .ISUNTY()/代码>共享相同的实现,那么您可以考虑将实现移动到公共基类,并为该基类编写测试。


仅仅因为类共享相同的接口,并不意味着它们的测试需要集中和耦合。

分别为每个实现创建一个测试:
QuickListTest
EfficientMemoryListTest

QuickListTest.java

但是
JUnit
如果基类是抽象的,那么如何从基类运行测试呢。JUnit将在超类上运行实现的方法。
public class QuickListTest extends ListBase {   
    @Test
    public void shouldBeEmpty() throws Exception {   
        assertThatIsEmpty(new QuickList<Integer>());   
    }    
}
public abstract class ListBase {    
    protected void assertThatIsEmpty(QuickList<Integer> actual) {
        assertThat(actual).isEmpty();
    }
}