Java中使用泛型的类应编写哪些单元测试?

18

以此文章中定义的JpaDao类为例:

public abstract class JpaDao<K, E> implements Dao<K, E> {
    protected Class<E> entityClass;

    @PersistenceContext
    protected EntityManager entityManager;

    public JpaDao() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        this.entityClass = (Class<E>) genericSuperclass.getActualTypeArguments()[1];
    }

    public void persist(E entity) { entityManager.persist(entity); }

    public void remove(E entity) { entityManager.remove(entity); }

    public E findById(K id) { return entityManager.find(entityClass, id); }
}

在单元测试方面,是将所有现有实体(OrderCustomerBook等)都写上单元测试最好呢,还是只为一个实体编写单元测试就可以了,就像这个其他问题中所暗示的那样?在使用泛型的情况下,有关于Java类进行单元测试的最佳实践吗?

6个回答

8
你可以为那些继承了此类的实体编写一个抽象测试类。
例如:
public abstract class JpaDaoTest<K,E> {

    abstract protected E getEntity();
    abstract protected JpaDao getDAO();

    @Test
    public void testPersistCreatesEntity()
    {
         JpaDao dao = getDAO();
         dao.persist(getEntity());
         // assert
     }
}

你所实现的通用类应该能够像通用类一样进行测试,假设 getEntity() 正确设置了关系依赖。

因此,通过为所有通用子类的测试用例子类化此测试类,您可以免费获得这些测试。


2

来自JUnit FAQ:

4)在什么情况下应该测试get()和set()方法?

单元测试旨在减轻担心某些东西可能会出错的恐惧。如果您认为get()或set()方法可能会合理地出错,或者实际上已经导致了缺陷,那么请编写一个测试。

简而言之,测试直到您有信心。您选择测试的内容是主观的,基于您的经验和信心水平。记得要实用并最大化您的测试投资。

它还指出:

“测试直到恐惧变成无聊。”

我认为您的问题与泛型无关,因为即使您不使用泛型,问题仍然是相同的。在这种情况下,我会选择测试一个对象(真实的或为测试目的而制作的)。随着您发现问题,请编写测试以解决这些特定的缺陷。


常见问题:在什么情况下应该测试 get() 和 set() 方法? - Rohim Chou

1
如果使用不同的实体类型会导致执行不同的代码,则需要编写单独的测试用例。
我会在一个通用的测试集中尽可能多地测试只使用一个实体类型。如果大部分代码都将所有实体视为相同,则无需多次测试。我会为任何需要特定实体DAO具有不同行为的特殊行为设置单独的测试用例。

1

和 BalusC 一样,我推荐测试具体实现。原因是它符合“你不需要它”的原则。只添加足够的测试,以便您正在尝试实现的用例通过。然后,在添加更多用例时,添加更多单元测试。


0
如果我需要测试类在类型语义方面的行为,我会检查类型不变量。换句话说,尝试建立一些断言,这些断言对于所有类型组合都是正确的,而不仅仅是您预期使用的类型,还包括宇宙中尚未发明的类型。例如:
private <K, E> void testTypes(K k, E e) {
    JpaDao<K, E> dao = new JpaDaoImpl<K, E>();

    dao.persist(e);

    assertEquals(dao.getById(e.getId()).getClass(), e.getClass());
}

@Test
public void testIntegerAndOrder() {
    this.<Integer, Order>testTypes(10, new Order());
}

看,无论 KE 是什么类型,都应该满足这些断言(testIntegerAndOrder() 方法使用具体类型值测试此断言)。

当然,这应该与单元测试一起使用,实际上测试类型变量的某些特定值的行为。这将非常类似于您在任何 JUnit 教程中找到的单元测试。例如:

@Test
public void testDao() throws Exception {
    JpaDao<Integer, Order> dao = getDao();

    Order order = ...;
    order.setId(10);

    dao.persist(order);

    assertEquals(order, dao.findById(10));
}

请看断言语义在这里的不同之处:此测试使用变量ID的具体值而非上一个测试中的类型变量,来测试存储对象是否保存了其ID。

0

测试具体类可以避免以后覆盖它的问题。

编写通用测试很美好,但并不安全。

在开发过程中,您可以复制大部分单元测试,稍后再自定义测试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接