在 Java 中使用泛型为类编写啥单元测试?

Posted

技术标签:

【中文标题】在 Java 中使用泛型为类编写啥单元测试?【英文标题】:What unit test to write for a class using generics in Java?在 Java 中使用泛型为类编写什么单元测试? 【发布时间】:2011-06-11 08:49:10 【问题描述】:

以这个article中定义的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); 

最好为应用程序中的所有现有实体(OrderCustomer、Book 等)编写单元测试,还是只为一个实体编写单元测试,如提示的那样?通过这个other question?有没有关于使用泛型对 Java 类进行单元测试的最佳实践?

【问题讨论】:

【参考方案1】:

你可以为这个子类的实体编写一个抽象测试类。

例如:

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】:

如果使用不同的实体类型导致执行不同的代码,那么您需要一个单独的测试用例。

我会在一组仅使用一种实体类型的通用测试中进行尽可能多的测试。如果您的大部分代码对所有实体都一视同仁,则无需多次对其进行测试。我会为特定实体 DAO 具有不同行为的任何特殊行为设置单独的测试用例。

【讨论】:

【参考方案3】:

来自 JUnit 常见问题解答:

4) 在什么条件下我应该测试 get() 和 set() 方法? 单元测试旨在减轻对某些事情可能会崩溃的恐惧。如果您认为 get() 或 set() 方法可以合理地破坏,或者实际上导致了缺陷,那么请务必编写一个测试。 简而言之,测试直到您有信心为止。您选择测试的内容是主观的,取决于您的经验和信心水平。切记要实用并最大限度地提高您的测试投资。

它还指出:

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

我认为您的问题不是针对泛型的,因为即使您不使用泛型,问题仍然是相同的。在这种情况下,我会选择测试一个对象(真实的或罐装的用于测试目的)。当您发现问题时,然后编写测试以解决这些特定缺陷。

【讨论】:

【参考方案4】:

与 BalusC 一样,我建议测试具体的实现。这样做的原因是它符合“你不需要它”的原则。添加足够的测试,以便您尝试实现的用例通过。然后,随着您添加更多用例,添加更多单元测试。

【讨论】:

【参考方案5】:

如果我需要测试类在类型语义方面的行为,我会去检查类型不变量。换句话说,尝试为 all 类型组合建立一些正确的断言,不仅是您希望使用的那些,而且是宇宙中的任何类型,包括那些尚未发明的类型。例如:

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 的断言。

【讨论】:

【参考方案6】:

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

进行通用测试很漂亮,但并不安全。

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

【讨论】:

以上是关于在 Java 中使用泛型为类编写啥单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

现在有啥好用的java开发框架

在编写单元测试时如何知道要测试啥? [关闭]

单元测试

单元测试经典三问:是什么,为什么,怎么做?

读《单元测试之道Java版》

单元测试集成测试