有没有一个Java实用程序可以对两个对象进行深入比较?[已关闭]

2022-08-31 10:18:58

如何根据测试中的字段值“深入”比较两个未实现 equals 方法的对象?


原始问题(由于缺乏精度而关闭,因此不符合SO标准),出于文档目的而保留:

我正在尝试为大型项目中的各种操作编写单元测试,我想知道是否有一个现有的类能够在某个地方获取两个相同类型的对象,进行深入比较,并说它们是否相同?clone()


答案 1

Unitils具有以下功能:

通过反射进行相等断言,具有不同的选项,例如忽略 Java 默认值/空值和忽略集合的顺序


答案 2

我喜欢这个问题!主要是因为它几乎没有得到过回答或回答不好。就像还没有人弄清楚一样。维尔京:)

首先,甚至不要考虑使用.在 javadoc 中定义的 契约是等价关系(自反、对称和传递),而不是相等关系。为此,它还必须是反对称的。它的唯一实现是(或者可能是)真正的相等关系是 中的那个。即使您确实使用了比较图表中的所有内容,违反合同的风险也相当高。正如Josh Bloch在 Effective Java 中指出的那样,平等的契约很容易被打破:equalsequalsequalsjava.lang.Objectequals

“根本没有办法在保留等价合约的同时扩展可实例化的类并添加一个方面”

此外,布尔方法到底有什么好处呢?实际上封装原始和克隆之间的所有差异会很好,你不觉得吗?另外,我在这里假设您不想为图中的每个对象编写/维护比较代码而烦恼,而是在寻找随着源随时间变化而随其变化而扩展的东西。

所以,你真正想要的是某种状态比较工具。该工具的实现方式实际上取决于域模型的性质和性能限制。根据我的经验,没有通用的灵丹妙药。而且在大量的迭代中,它会很慢。但是,为了测试克隆操作的完整性,它将很好地完成工作。两个最佳选择是序列化和反射。

您将遇到的一些问题:

  • 集合顺序:如果两个集合包含相同的对象,但顺序不同,是否应将其视为相似?
  • 要忽略哪些字段:瞬态?静态的?
  • 类型等效性:字段值是否应具有完全相同的类型?或者一个可以扩展另一个吗?
  • 还有更多,但我忘记了...

XStream非常快,与XMLUnit相结合,只需几行代码即可完成这项工作。XMLUnit很好,因为它可以报告所有差异,或者只是停留在它找到的第一个差异。它的输出包括到不同节点的xpath,这很好。默认情况下,它不允许无序集合,但可以将其配置为这样做。通过注入特殊的差分处理程序(称为 a),您可以指定处理差分的方式,包括忽略顺序。但是,一旦您想执行最简单的自定义之外的任何内容,就很难编写,并且详细信息往往会绑定到特定的域对象。DifferenceListener

我个人更喜欢使用反射来循环遍历所有声明的字段,并向下钻取到每个字段,并跟踪差异。警告:不要使用递归,除非你喜欢堆栈溢出异常。使用堆栈(使用 a 或某些内容)将内容保持在范围内。我通常忽略瞬态和静态字段,并且跳过我已经比较过的对象对,因此如果有人决定编写自引用代码,我不会最终陷入无限循环(但是,无论如何,我总是比较原始包装器,因为相同的对象ref经常被重用)。您可以预先配置内容以忽略集合排序并忽略特殊类型或字段,但我喜欢通过注释在字段本身上定义我的状态比较策略。恕我直言,这正是注释的用途,以便在运行时提供有关类的元数据。像这样:LinkedList


@StatePolicy(unordered=true, ignore=false, exactTypesOnly=true)
private List<StringyThing> _mylist;

我认为这实际上是一个非常困难的问题,但完全可以解决!一旦你有了适合自己的东西,它就真的,真的,方便:)

所以,祝你好运。如果你想出一些纯粹的天才,别忘了分享!


推荐