使用ScalaTest比较集合内容

Mic*_*val 39 unit-testing scala scalatest

我正在尝试对一些非常集合的Scala进行单元测试.这些集合作为返回Iterable[T],因此我对集合的内容感兴趣,即使基础类型不同.这实际上是两个相关的问题:

  1. 如何断言两个有序集合包含相同的元素序列?
  2. 如何断言两个无序集合包含相同的元素集?

总之,我在ScalaTest中看到Scala等效的NUnit CollectionAssert.AreEqual(有序)和CollectionAssert.AreEquivalent(无序):

Set(1, 2) should equal (List(1, 2))          // ordered, pass
Iterable(2, 1) should equal (Iterable(1, 2)) // unordered, pass
Run Code Online (Sandbox Code Playgroud)

Chr*_*ner 88

同时你可以使用

Iterable(2, 1) should contain theSameElementsAs Iterable(1, 2)
Run Code Online (Sandbox Code Playgroud)

要测试有序集,您必须将其转换为序列.

Set(1, 2).toSeq should contain theSameElementsInOrderAs List(1, 2)
Run Code Online (Sandbox Code Playgroud)

  • 有没有办法让`sbt`提供比'....不包含与...相同的元素的更好的输出?具体来说,如果能告诉我大型系列中缺少什么,那就太好了. (19认同)
  • re:第二个例子.`Set`没有定义的顺序,因此转换为`Seq`时的顺序基本上是随机的,你应该永远不会有一个结果依赖于该顺序的测试.如果你使用一个有序的Set,如`sortedSet`和`toSeq`,除了一个更有吸引力的名字之外,``应该包含与`should equal`不同的`SameElementsInOrderAs`? (3认同)

Lui*_*hys 21

您可以尝试.toSeq订购集合和.toSet无序集合,它可以根据我的理解捕获您想要的内容.

以下通行证:

class Temp extends FunSuite with ShouldMatchers {
  test("1")  { Array(1, 2).toSeq should equal (List(1, 2).toSeq) }
  test("2")  { Array(2, 1).toSeq should not equal (List(1, 2).toSeq) }
  test("2b") { Array(2, 1) should not equal (List(1, 2)) }  
  test("3")  { Iterable(2, 1).toSet should equal (Iterable(1, 2).toSet) }
  test("4")  { Iterable(2, 1) should not equal (Iterable(1, 2)) }
}
Run Code Online (Sandbox Code Playgroud)

BTW a Set没有订购.

编辑:为避免删除重复的元素,请尝试toSeq.sorted.以下传递:

  test("5")  { Iterable(2, 1).toSeq.sorted should equal (Iterable(1, 2).toSeq.sorted) }
  test("6")  { Iterable(2, 1).toSeq should not equal (Iterable(1, 2).toSeq) }
Run Code Online (Sandbox Code Playgroud)

编辑2:对于无法对元素进行排序的无序集合,您可以使用以下方法:

  def sameAs[A](c: Traversable[A], d: Traversable[A]): Boolean = 
    if (c.isEmpty) d.isEmpty
    else {
      val (e, f) = d span (c.head !=)
      if (f.isEmpty) false else sameAs(c.tail, e ++ f.tail)
    }
Run Code Online (Sandbox Code Playgroud)

例如(注意使用'a 'b 'c没有定义排序的符号)

  test("7")  { assert( sameAs(Iterable(2, 1),    Iterable(1, 2)     )) }
  test("8")  { assert( sameAs(Array('a, 'c, 'b), List('c, 'a, 'b)   )) }
  test("9")  { assert( sameAs("cba",             Set('a', 'b', 'c') )) }
Run Code Online (Sandbox Code Playgroud)

替代sameAs实施:

  def sameAs[A](c: Traversable[A], d: Traversable[A]) = {
    def counts(e: Traversable[A]) = e groupBy identity mapValues (_.size)
    counts(c) == counts(d)
  }
Run Code Online (Sandbox Code Playgroud)