【问题标题】:test equality of two iterators?测试两个迭代器的相等性?
【发布时间】:2012-03-17 19:23:43
【问题描述】:

如何使用 JUnit 测试两个迭代器的相等性?

是否有任何内置方法,或者只是通过比较其中的每个元素?

谢谢, 斯里拉姆

【问题讨论】:

  • 我想我从来没有考虑过这个问题。
  • 请记住,Iterator 可以任意长(甚至无限长)。如果有一个内置的方法来测试两个迭代器的相等性并且它在合理的时间内工作,我可以使用它来生成有趣且可发布的数学证明。
  • 另外,测试内容是一种破坏性操作。

标签: java junit iterator junit4


【解决方案1】:

您不能(也不需要)测试迭代器的相等性,只能测试底层集合的相等性。为此,您可以遍历两者并依次比较每对元素,正如您所猜测的那样。请注意,这有效地消耗了至少一个迭代器。并且结果取决于测试开始时迭代器的状态,所以这种方法很脆弱。因此,最好尽可能掌握底层集合并直接测试它们的相等性(使用他们的equals 方法)。

为什么要测试两个迭代器的相等性?如果您解释您的具体问题,我们或许可以提供更好的替代方案。

【讨论】:

  • 不一定有基础集合。如果有一个底层集合,它可能是无限的。
  • 我有一个返回迭代器类型的函数。 *.com/questions/9747291/… 。我正在尝试测试。
  • @emory,说得好,尽管这些听起来更像是函数式语言而不是 Java 的案例。
  • @sriram,为什么你需要这个方法来返回一个迭代器而不是你实际拥有的List<String>
【解决方案2】:

没有健全的方法来测试Iterators 的相等性。

如果在这种情况下发疯是一种选择,您可能想要深入研究您正在测试的特定迭代器类型的实现,并使用反射来访问私有内容并进行比较(我敢肯定,对源代码进行了足够的分析代码,例如,您会发现两个 ListIterators 需要保持相等)。

或者如果它是你自己的迭代器类型,那么导出一些可以帮助你的变量并使用它们而不是反射。

遍历和比较元素只是一个弱保证,因为您可能会遍历您的集合的克隆,这意味着迭代器看起来相同,但实际上并非如此。

不要这样做。

【讨论】:

  • >"...,因为您可能正在迭代您的集合的克隆,这意味着迭代器看起来相同,但实际上不同。"Collections 和Iterables 的情况下存在。在测试场景中,检查迭代器的行为可能是有意义的,因为有时您别无选择,只能处理给定的 API,无论它设计得多么好。
  • 您可以拥有原始集合的精确副本和两个迭代器,每个迭代器都指向同一位置。如果你只是通过这些迭代器比较容器值,你会认为迭代器是相等的,但实际上它们指向不同的集合。
  • 好的,所以您的想法是,在比较迭代器时,您只希望它们在它们的基础集合相同时相等,这当然意味着首先存在这样的基础集合。我认为这没有必要,因为即使官方 Javadoc 将 Iterator 定义为“集合上的迭代器”(使用小写的 'c'),Iterator 接口也无法提供访问集合的方法,但只有一个又一个元素。所以只给Iterator,在定义相等性时,我们甚至不能真正谈论底层集合。
  • 在实践中,(几乎)总是有一个底层集合,如果你真的需要,你可以通过反射访问它。我写的是可行的,但高度特定于实现且不可移植,因此在我的第二段开头的警告。
  • 好的,所以我们同意在一般情况下不应该使用反射来访问迭代器的底层集合。
【解决方案3】:

Iterators 没有“经典”的相等概念,除了对象标识,因为它们以“最坏”的方式是可变的。

在 JUnit 场景中,最好将 next() 返回的值收集到一个列表中,例如使用 Guava 的ImmutableList.copyOf(Iterator<T>),然后按照this SO answer 中的描述继续使用assertThat(a, is(b))

【讨论】: