【问题标题】:How to debug something that works under Java 7 but not under Java 8如何调试在 Java 7 下有效但在 Java 8 下无效的东西
【发布时间】:2015-09-30 16:05:57
【问题描述】:

我有一个带有单元测试的项目,它在 Java 7 下工作,但在 Java 8 下不工作。有没有很好的方法来调查这些事情? (我确信测试是正确的;这表明实现中存在一个微妙的错误。)

真的,我想我想要一种快速识别代码路径分歧的方法。但这很难,因为通过 JDK 在非常低级别的代码路径中可能存在各种差异,我不想陷入由于微小优化而导致的无关差异。

所以最好的办法是询问路径分歧的顶层跟踪;然后,从该点之前开始,询问路径分歧的第二级跟踪;等等。

但我不知道是否有办法做到这一点。如果我没有系统的方法,我担心我会浪费很多时间。

顺便说一句,代码是 Apache Phoenix 存储库,在 Java 8 下,我遇到以下错误:

Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.006 sec <<< FAILURE! - in org.apache.phoenix.schema.PMetaDataImplTest
testEviction(org.apache.phoenix.schema.PMetaDataImplTest)  Time elapsed: 0.006 sec  <<< FAILURE!
java.lang.AssertionError: expected:<3> but was:<2>
    at org.junit.Assert.fail(Assert.java:88)
    at org.junit.Assert.failNotEquals(Assert.java:834)
    at org.junit.Assert.assertEquals(Assert.java:645)
    at org.junit.Assert.assertEquals(Assert.java:631)
    at org.apache.phoenix.schema.PMetaDataImplTest.testEviction(PMetaDataImplTest.java:98)

【问题讨论】:

  • 你只调试代码,单步执行怎么样?
  • @Andreas 我可以做到,是的。但我认为,这将归结为 JDK 集合实现的细节。而且我还需要两台机器才能使用不同的 JDK 同时单步执行两次。
  • 为什么?如果你需要的话,你可以在一台机器上安装多个 JDK 和 IDE。
  • 不要浪费时间尝试比较两个 JRE。对失败的测试进行一步调试,并将代码所做的与代码应该做的进行比较。如果这太复杂了,您应该重新考虑单元测试的粒度,即将测试分成更小的测试,直到找到损坏的操作。
  • @Holger 我怀疑你是对的,这是最好的方法。我只是希望有一些东西可以帮助分析这种情况。您可以看到它可能发生在其他情况下:您将依赖项更新到新版本,然后事情就中断了,您想知道确切的位置。单元测试的粒度很重要,但在这种情况下,它们不是我的测试,所以我无法控制它。

标签: java unit-testing java-8 java-7 phoenix


【解决方案1】:

Java 7 和 Java 8 之间最明显的变化之一是对 how hash data structures handle collisions 的更改 - 以前使用的是链表,现在条目存储在平衡树中。在某些情况下,这会影响这些数据结构的迭代顺序。这不是语言回归,因为这些数据结构没有明确指定迭代顺序,但是很容易编写粗心的代码和假设某个顺序的测试。

在极少数情况下,此更改可能会更改 HashMapHashSet 的迭代顺序。没有为 HashMap 对象指定特定的迭代顺序 - 任何依赖于迭代顺序的代码都应该被修复。

~Collections Framework Enhancements in Java SE 8

因此,在调试 Java 7 -> 8 失败时,我要做的第一件事就是寻找HashMapHashSetConcurrentHashMap 的误用。找到错误后,您有几个选择:

  • 将数据结构替换为明确提供迭代顺序的数据结构,例如LinkedHashMapTreeMapImmutableMap
  • 从您的生产代码中删除迭代顺序假设(例如假设某个键/值将是映射中的第一个元素)。
  • 改进您的测试以实际检查指定的行为(哪些元素)而不是未指定的行为(什么顺序)。通常测试数据会以易于编写但不正确的方式定义,例如使用内联数组语法int[] expected = {1,2,3},然后循环遍历元素。您可以使用 Guava 的静态构造函数 (ImmutableSet.of(1,2,3)) 或 Truth 的流畅断言语法 (assertThat(someSet).containsExactly(1, 2, 3)) 来简化此操作。

如果哈希排序被证明不是根本原因,您的问题可能会更加微妙,并且您最好的选择可能是按照建议使用调试器逐步完成。请务必至少浏览What's New in JDK 8 以获取线索。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 2017-01-09
    • 2014-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多