首页 > 解决方案 > java.util.Map 上的“应该包含 allOf”?

问题描述

如何在 Java Map 上执行 contains allOf 断言?

以下没有工作

val testMap = new java.util.LinkedHashMap[Int, Int]()
testMap.put(1,2)
testMap.put(2,4)
testMap.put(3,6)
testMap should contain allOf (1->2, 2->4, 3->6)

它给

{1=2, 2=4, 3=6} did not contain all of ((1,2), (2,4), (3,6))

文档说

Aggregating 伴随对象为 GenTraversable[E]、java.util.Collection[E]、java.util.Map[K, V]、String、Array[E] 类型提供 Aggregating[L] 的隐式实例。

http://www.scalatest.org/user_guide/using_matchers#workingWithAggregations

我究竟做错了什么?

Scala     v2.11
ScalaTest v3.1.1

标签: scalascalatestscala-java-interop

解决方案


或者考虑CollectionConverters

import scala.jdk.CollectionConverters._
testMap.asScala should contain allOf (1->2, 2->4, 3->6)

如果我们希望维护以下 DSL

testMap should contain allOf (1->2, 2->4, 3->6)

然后我们可以提供一个自定义的 typeclass 实例来比较Scala 元组Aggregating的相等性Entry

trait JavaMapHelpers {
  def javaEntryEqualsScalaTuple[K, V]: Equality[java.util.Map.Entry[K, V]] =
    (a: java.util.Map.Entry[K, V], b: Any) => b match {
      case (k, v) => a.getKey == k && a.getValue == v
      case _ => false
    }

  implicit def aggregatingNatureOfJavaMapWithScalaTuples[K, V, JMAP[k, v] <: java.util.Map[k, v]]: Aggregating[JMAP[K, V]] =
    Aggregating.aggregatingNatureOfJavaMap(javaEntryEqualsScalaTuple)

  def javaMap[K, V](elements: (K, V)*): java.util.LinkedHashMap[K, V] = {
    val m = new java.util.LinkedHashMap[K, V]
    elements.foreach(e => m.put(e._1, e._2))
    m
  }
}


class JavaMapSpec extends AnyFlatSpec with Matchers with JavaMapHelpers {
  "Java Map" should "be checkable with Scala tuples" in {
    javaMap((1,2), (2,4), (3,6)) should contain allOf (1->2, 2->4, 3->6)
  }
}

定义将 JavaEntry与 Scala 元组进行比较的自定义相等性是有效的,因为在Java map 上containsAllOf调用entrySet然后检查提供Equality

def containsAllOf(map: JMAP[K, V], elements: scala.collection.Seq[Any]): Boolean = {
  checkAllOf(map.entrySet.asScala, elements, equality)
}

推荐阅读