【问题标题】:Test two instances of object are equal JUnit [duplicate]测试对象的两个实例是否相等 JUnit [重复]
【发布时间】:2014-12-22 15:35:10
【问题描述】:

我有两个对象 AB。 Object A 是我在 JUnit 测试期间得到的实际结果。对象B 是我进行实际的结束数据库调用并假设为预期审查。我需要断言两个对象实例 ABvalue 中是相等的,而不是实际对象。

我们在 JUnit 中有一个名为 assertEquals(obj expected, obj actual) 的方法,但我不希望这样。

有没有办法或解决方法来达到同样的效果?

【问题讨论】:

  • 为了检查两个对象是否具有相同的值,我使用以下命令:(success) assertThat(new Question("title", "id"), is(new Question("title", "id"))); (fail) assertThat(new Question("title1", "id1"), is(new Question("title", "id"))); 使用以下导入 import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.CoreMatchers.is;

标签: java junit


【解决方案1】:

想一想你想要达到的目标。您想测试对象身份还是验证两个对象具有完全相同的数据?根据您对 assertEquals 的建议,我猜您想逐个字段地进行。

如果物体很浅,你可以使用

assertThat(actual, samePropertyValuesAs(expected));

但是,当对象是复合对象时,这会失败。如果你想遍历整个图表,你可以使用 sameBeanAs 匹配器,我们写了一段时间来解决这个问题:

assertThat(actual, sameBeanAs(expected));

如果您使用 AssertJ,那么您还可以使用如下内置功能:

assertThat(actual).isEqualToComparingFieldByField(expected);

于 06/21 更新 - 显然已弃用并已替换为:

assertThat(actual).usingRecursiveComparison().isEqualTo(expected)

你不想做的一件事是覆盖 equals 方法,因为将来可能会改变以适应业务需求。

【讨论】:

  • 你知道我们可以使用的任何 Hamcrest 匹配器吗?
  • samePropertyValuesAs 是一个内置的 Hamcrest 匹配器。 sameBeanAs 是我们在 Shazam 编写的自定义 Hamcrest 匹配器,用于解决这个确切问题
  • 如果对象中有对象,则使用 assertThat(actual).isEqualToComparingFieldByFieldRecursively(expected)。
  • 只有 shazamcrest 到 JSON 的转换和比较有助于比较 POJO 和嵌套对象:assertThat(actual, sameBeanAs(expected));
  • 因为isEqualToComparingFieldByField 现已弃用,请参阅usingRecursiveComparison,例如:assertThat(actual).usingRecursiveComparison().isEqualTo(expected);
【解决方案2】:

如果你想要深度平等,可以使用 Commons Lang3 EqualsBuilder#reflectionEquals()

Assert.assertTrue(EqualsBuilder.reflectionEquals(expected,actual));

【讨论】:

  • 这需要您在所有级别上实现 equals 和 hashcode,这使得它没有那么有用。更有用的是在原始数据类型之前执行深度比较。
  • 不适用于嵌套对象,尽管它们具有相同的字段和值,但实例不同。
【解决方案3】:

使用 assertj,您可以断言这 2 个对象的每个成员!

例如assertThat(actual).isEqualToComparingFieldByField(expected);

【讨论】:

  • 不能使用这个。 Hamcrest 的 assertThat 接受两个参数。
【解决方案4】:

assertEquals() 在你的对象上调用equals(),这是没有办法的。你可以做的是在你的课堂上实现类似public boolean like(MyClass b) 的东西,你可以在其中比较你想要的任何东西。然后,您可以使用assertTrue(a.like(b)) 检查结果。

【讨论】:

  • 这意味着使用纯粹用于测试的方法污染您的生产代码。同样使用 assertTrue 绝对不会诊断/为什么/测试失败
  • 我同意用测试代码污染生产代码,但不同意诊断测试失败的原因。如果失败,则失败是因为实际对象与预期的“不一样”。如果您想要更精确的信息,请为每个相关字段添加一系列断言。
  • 您从中获得的诊断类似于“预期为真:得到假”。如果您修改测试以更好地利用断言,您不需要做任何其他工作。如果您看到我的回答,所有建议都会产生质量诊断,不仅告诉测试失败,而且告诉原因
  • 我不熟悉 junit 匹配器,我会研究一下,听起来就是这个问题的问题。
  • 您的 JUnit 世界即将变得更大 :)
【解决方案5】:

您需要为您的班级覆盖equalshashCode 方法。之后assertEquals(obj expected, obj actual) 将不再检查引用,而是使用您在equals 方法中实现的逻辑。

【讨论】:

  • 我认为这是非常糟糕的做法。您重写 equals 纯粹是为了满足需要逐字段比较的测试。如果等价合约稍后发生变化,那么您的测试仍然会通过,但不会从根本上破坏
  • @MrWiggles 如果我们有 2 个 Some class X 的实例,那么拥有一个像样的 equal 实现不是更好,所以每当我们需要比较这些对象时,我们可以依赖 equals 实现而不是默认equals实现继承自Object类
  • 如果您的生产代码需要等号,那么可以,例如,如果您将其放在 Set 中。在这种情况下,覆盖字段检查的问题是您执行默认的 equals 实现检查每个字段。如果稍后由于真正的商业原因,equals 方法应该更改,例如仅在 ID 上进行比较,最初需要它的测试现在已损坏,但不会失败。此外,在此测试中使用 equals 不会为您提供有关对象为何不同的诊断信息,只是它们不同
  • @MrWiggles 我认为在那种情况下我们最好使用匹配器
  • 我不明白为什么这是不好的做法。 equals() 方法必须正确地将两个对象标识为相等。这将是“真实”应用程序和单元测试中完全相同的条件。如果您在应用程序中需要非常专业的比较策略,您可能通过更改 equals() 来做错了,而应该使用 Comparator。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-30
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多