在 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);
最好为应用程序中的所有现有实体(Order
、Customer
、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());
请看,无论K
和E
是什么类型,断言都应保持(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 中使用泛型为类编写啥单元测试?的主要内容,如果未能解决你的问题,请参考以下文章