Java 我应该单元测试hashCode/equals/toString吗?

Java 我应该单元测试hashCode/equals/toString吗?,java,unit-testing,code-coverage,qa,Java,Unit Testing,Code Coverage,Qa,编写Java类时,使用IDE生成方法(如 toString() equals() hashCode() 但是,一旦您使用IDE生成它们,它们就成为您的代码库(在SCM中)的一部分,因此所有质量度量方法都适用 特别是equals和hashcode方法包含很多条件。如果我不编写单元测试,代码覆盖率(行、条件、变异)的分数就相当低,特别是当被测试的类没有那么大的时候 一些覆盖率工具支持过滤(如cobertura),而其他工具(如jacoco)不支持过滤。但是覆盖工具只揭示了一个症状——未经测试的代

编写Java类时,使用IDE生成方法(如

  • toString()
  • equals()
  • hashCode()
但是,一旦您使用IDE生成它们,它们就成为您的代码库(在SCM中)的一部分,因此所有质量度量方法都适用

特别是equals和hashcode方法包含很多条件。如果我不编写单元测试,代码覆盖率(行、条件、变异)的分数就相当低,特别是当被测试的类没有那么大的时候

一些覆盖率工具支持过滤(如cobertura),而其他工具(如jacoco)不支持过滤。但是覆盖工具只揭示了一个症状——未经测试的代码——因此我不是在问是否抑制/忽略症状,而是如何处理根本原因

问题是:我应该为这些方法编写单元测试吗

  • 如果是,有什么好的理由这样做?什么是明智的做法
  • 若否,原因为何

一般来说,我并不要求生成类,如JAXB POJO、WS-Clients等,它们可以很容易地自动生成并从覆盖率分析中排除。

对于外部库也是如此-在生成这些类时,不应该测试
equals
hashcode
方法。检查覆盖率的插件应该有一些机制来忽略生成的源代码


并没有很好的理由来测试生成的代码,若这是在类中或整个类中生成的方法,则并没有区别


如果你依赖外部机制,你应该相信它是正确创建的。

这些方法本身是无用的。如果不在集合中使用这些类(如
HashSet
/
HashMap
),或者如果从不检查这些类实例是否相等,则不需要进行单元测试。在这种情况下,我会禁用生成它们的插件,正如@ByeBye所建议的


但是,如果你真的这样做了,你需要单元测试。如果不正确的实现可能导致应用程序失败或行为不正确-此实现必须包含单元测试。

IDE生成的hashCode/equals的问题在于它可能与对象本身不同步(例如,当您添加新字段时)。因此,我建议为hashCode和equals创建测试

当然,手工书写这些内容是次优的。您可以使用自动化工具(如project)使这些工具成为一行程序


toString是另一种野兽,因为它没有定义任何契约。如果您使用toString只是为了获得更好的调试体验,我不会对其进行测试,而是将其从覆盖率计算中删除。

如果生成这些方法,您可能还应该为其生成测试;-)

手工测试这些方法可能会很麻烦,但根据您希望通过测试确保什么,测试这些方法也可能是值得的。反问:你会测试日志语句吗

这真的取决于你想要完成什么。有些人会说:不要,其他人可能会说:做吧

思考不测试此类方法的一些原因:

  • 生成的代码可能包含许多字段。测试它可能会导致许多不同的组合,这对于编写/维护来说非常麻烦,而且可能已经对生成器进行了足够好的测试?;-)
  • 通过对其实施测试,您不会获得任何价值。您的
    toString()
    将仅由日志或调试器使用,因此您根本不在乎
  • 您相信生成的代码对于
    hashcode
    equals来说足够安全
测试此类方法的原因:

  • 确保结果符合预期
  • 您希望确保,如果重新生成这些方法,它不会破坏以前的方法实现用法
  • 除了日志记录之外,您还使用了
    toString()
    -方法,不希望某些东西显示在那里。正如Hulk所说,您可能还希望确保某些内容甚至不会显示在日志中
但这些都是虚构的。在上一个项目中,我没有测试
toString()
equals
hashCode
,只是测试很少,因为这是不必要的,而且每个人都同意


这一切可能归结为:您希望您的代码有多安全,以及它对您(或您的企业或您的客户;-)的价值有多大。

是的,我会测试所有这些。这还不足以说明,不需要测试,因为它们是自动生成的。有些人很容易添加一个新字段,而忘记重新生成equals/hash代码和to字符串

对字符串的测试可能是最有争议的,但我认为它是必要的,尤其是当您登录应用程序时

正如其他人已经建议的,这可能是测试equals和hash代码的最佳方法

至于测试toString方法,请尝试。测试非常简单,如下所示:

@Test
public void testToString() {
    ToStringVerifier.forClass(User.class)
                  .withClassName(NameStyle.SIMPLE_NAME)
                  .verify();
}

如果生成equals&hashcode插件,则可以禁用该插件。即使只将
toString()
用于日志记录,也有一些东西是您不想在日志中找到的。测试您的
webSessionId
topSecretPassPassword
是否不包含在其中可能是有意义的。对,这可能是有意义的,以确保。“没有很好的理由测试生成的代码,如果这是在您的类或整个类中生成的方法,则没有区别。”是的,有。假设您今天为equals()方法生成了一段代码。您希望确保它在将来继续工作,因此需要为它添加一个单元测试。三个月后,有人向类添加了一个新属性,但他们没有更改测试。它应该会崩溃…仍然没有理由单独测试equals。当您使用示例map/set/tree结构时,您正在谈论测试行为。因此,请测试您的代码并提供