使用Hibernate进行单元测试时比较实体

时间:2009-06-03 08:08:34

标签: unit-testing hibernate junit entity

我在内存HSQLDB中运行JUnit测试。假设我有一个方法将一些值插入数据库,我正在检查方法是否正确插入了值。请注意,插入顺序并不重要。

@Test
public void should_insert_correctly() {
    MyEntity[] expectedEntities = new MyEntity[2];
    // init expected entities

    Inserter out = new Inserter(session); // out: object under test
    out.insert();

    List list = session.createCriteria(MyEntity.class).list();

    assertTrue(list.contains(expectedEntities[0]));
    assertTrue(list.contains(expectedEntities[1]));
}

问题是我无法将预期实体与实际实体进行比较,因为期望的id和实际的id是不同的。由于MyEntity的setId()是私有的(为了防止显式设置id),我不能将所有实体的id设置为0并进行比较。

如何比较两个结果集而不管它们的ID?

3 个答案:

答案 0 :(得分:2)

我发现这更实用。我不是一次获取所有结果,而是根据标准获取结果并断言它们不是空的。

public void should_insert_correctly() {
    Inserter out = new Inserter(session); // out: object under test
    out.insert();

    Criteria criteria;

    criteria = getCriteria(session, 0);
    assertNotNull(criteria.uniqueResult());

    criteria = getCriteria(session, 1);
    assertNotNull(criteria.uniqueResult());
}

private Criteria getCriteria(Session session, int i) {
    Criteria criteria = session.createCriteria(MyEntity.class);
    criteria.add(Restrictions.eq("x", expectedX[i]));
    criteria.add(Restrictions.eq("y", expectedY[i]));
    return criteria;
}

答案 1 :(得分:0)

有状态实体不应该覆盖equals - 也就是说,实体应该通过引用标识进行相等性比较 - 因此List.contains将无法正常工作。

我所做的是使用反射来比较原始实体和重新加载的实体的字段。遍历对象字段的函数忽略瞬态字段和注释为@Transient的字段。

我发现我不需要忽略id。当对象首次刷新到数据库时,Hibernate会为其分配一个id。重新加载时,该对象将具有相同的ID。

测试中的缺陷是您没有设置事务边界。您需要在一个事务中保存对象。当您提交该事务时,Hibernate会将对象刷新到数据库并分配其ID。然后在另一个事务中从数据库中加载实体。您将获得另一组具有相同ID和持久(即非瞬态)状态的对象。

答案 2 :(得分:-1)

我会尝试在Object.equals(Object)课程中实施MyEntity方法。

List.contains(Object)使用Object.equals(Object)(来源:Java 6 API)来确定对象是否在此列表中。

方法session.createCriteria(MyEntity.class).list();返回 new 实例的列表,其中包含您插入的值(希望如此)。
所以你需要比较这些值。这可以通过Object.equals(Object)

的实施轻松完成

澄清编辑:
您可以忽略equals方法中的ID,以便比较仅关注“实际值”。

YAE(又一编辑):
我建议您阅读有关equals()方法的文章:Angelika Langer: Secrets Of Equal。它很好地解释了所有背景信息。