在开发 Java 应用程序时,我经常重写 Object 方法(通常是 equals 和 hashCode)。我想要一些方法来系统地检查我是否遵守我的每个类的 Object 方法的合同。例如,我想要断言对于相等的对象,哈希码也相等的测试。我正在使用 JUnit 测试框架,所以最好我想要一些 JUnit 解决方案,我可以在其中自动生成这些测试,或者一些可以以某种方式访问我的所有类并确保合同得到遵守的测试用例。
我正在使用 JDK6 和 JUnit 4.4。
在开发 Java 应用程序时,我经常重写 Object 方法(通常是 equals 和 hashCode)。我想要一些方法来系统地检查我是否遵守我的每个类的 Object 方法的合同。例如,我想要断言对于相等的对象,哈希码也相等的测试。我正在使用 JUnit 测试框架,所以最好我想要一些 JUnit 解决方案,我可以在其中自动生成这些测试,或者一些可以以某种方式访问我的所有类并确保合同得到遵守的测试用例。
我正在使用 JDK6 和 JUnit 4.4。
公共静态无效checkObjectIdentity(对象a1,对象a2,对象b1){ 断言等于(a1,a2); 断言等于(a2,a1); assertNotSame(a1, a2); assertEquals(a1.hashCode(), a2.hashCode()); 断言假(a1.equals(b1)); 断言假(a2.equals(b1)); 断言假(b1.equals(a1)); 断言假(b1.equals(a2)); }
用法:
checkObjectIdentity(新整数(3),新整数(3),新整数(4));
想不出更好的了。发现错误时添加对 checkObjectIdentity 的新调用。
只是对这个问题的一些初步想法(这可以解释为什么整整一个小时后仍然没有答案!?;)
在实施该问题的解决方案时,似乎有两个部分:
1/检索我自己的每一个类。很简单,你给一个 jar 名称,Junit 测试初始化方法会:
2/ 测试每一个对象
......这就是问题所在:您必须实例化这些对象,即创建两个实例,并将它们用于 equals() 测试。
这意味着如果你的构造函数被接受参数,你必须考虑,
最后,并非为这些构造函数自动创建的每个参数都以功能方式有意义,这意味着其中一些值将无法构建实例,因为必须检测到 Assert:。
然而这似乎是可能的(如果你愿意,你可以把它变成一个代码挑战),但我想首先让其他 StackOverflow 读者回应这个问题,因为他们可能会看到一个比我更简单的解决方案。
为了避免组合问题并使测试相关的测试值接近实际代码本身,我建议定义一个专用注释,其中一个字符串代表构造函数的有效值。将位于您的一个对象的 equals() 覆盖方法的正上方。
然后将读取这些注释值,并组合从这些注释值创建的实例以测试 equals()。这将使组合的数量保持足够低
侧节点:一个通用的 JUnit 测试用例当然会检查,对于每个 equals() 测试,有:
这个问题没有“简单”的解决方案,除非你对你的类施加了严格的限制。
例如,如果您为给定类使用多个构造函数,如何确保在 equals/hash 方法中充分考虑所有参数?默认值怎么样?不幸的是,这些东西不能盲目地自动化。
也许我误解了这个问题(并且过于 CS),但听起来你所描述的问题在一般情况下是不可判定的。
换句话说,单元测试可以确保覆盖方法在所有输入上的工作方式与覆盖方法相同的唯一方法是在所有输入上进行尝试。在 equals 的情况下,这将意味着所有对象状态。
我不确定当前的任何测试框架是否会自动为您缩减和抽象可能性。
一个老问题的新答案,但在 2011 年 5 月Guava(以前的 Google Collections)发布了一个删除了很多样板的类,称为EqualsTester
. 您仍然必须创建自己的实例,但它负责将每个对象与自身、null、平等组中的每个对象、每个其他平等组中的每个对象以及不应匹配的秘密实例进行比较。它还检查所有这些组合的a.equals(b)
含义。a.hashCode() == b.hashCode()
来自 Javadoc 的示例:
new EqualsTester()
.addEqualityGroup("hello", "h" + "ello")
.addEqualityGroup("world", "wor" + "ld")
.addEqualityGroup(2, 1 + 1)
.testEquals();
[这里的社区帖子,不涉及业力;)]
这是另一个代码挑战:
一个java 类,实现了一个 JUnit 测试用例,具有一个能够自行启动 JUnit 的 main 方法!
该课程还将:
测试方法接受一个类名参数(这里:它将是它自己),检查具有该名称的类是否有一个带有“有趣值”注释的 equals() 覆盖方法。
如果是这样,它将根据注释构建(自身)适当的实例,并测试 equals()
这是一个自包含的测试类,它定义了一种机制,该机制能够推广到任何具有带注释的覆盖 equals() 函数的类。
请使用JDK6和JUnit4.4
该类应该被复制粘贴到一个空的java项目的适当包中......然后运行;)
为了增加一些想法,回应尼古拉斯(见评论):
代表潜在测试数据的注释应该永远不会出现在课堂上吗?......嘿,这可能是一个很好的问题:)
我有一个第一个粗略的实现,在这里只使用原始参数使用 Constructor 进行 equals 测试。只需将它复制粘贴到 test.MyClass.java 文件中并运行它。
警告:1720 行代码(findbugs 中的 0 个错误,“修改”检查样式中的 0 个错误,所有函数的圈复杂度低于 10)。
查看所有代码:Auto-test for equals function in java classes through annotations
我认为 VonC 走在正确的轨道上,但我什至会满足于一些不太复杂的东西,例如接受 .class 对象(正在测试 Object 方法)的参数化测试,然后是可变数量的构造函数参数。然后,您必须使用反射来找到与传入参数的类型匹配的构造函数,并调用构造函数。此测试将假定传递给它的参数将创建对象的有效实例。
这个解决方案的缺点是你必须用这个测试类“注册”你想要测试的每个类,并且你必须确保向构造函数提供有效的输入,这并不总是容易的。有鉴于此,我对这是否比手动编写每个类的所有测试更多或更少的工作持怀疑态度。
如果您认为这可行,请投票...如果您希望我将其更多地刷新,请发表评论(如果事实证明这是一个可行的解决方案,我可能还是会这样做)