如何在Java Map上执行contains allOf断言?ScalaTest问题排查
问题原因分析
你遇到的问题核心在于:Scala里的1->2生成的是Tuple2[Int, Int]实例,但java.util.LinkedHashMap中的元素是java.util.Map.Entry[Int, Int]类型,这两个类型完全不兼容——ScalaTest的contains allOf断言会逐个检查传入的元素是否存在于集合中,自然会判定“找不到这些Tuple元素”。
虽然ScalaTest的Aggregating伴生对象确实为java.util.Map提供了隐式支持,但它是基于Java Map的Entry元素来做匹配的,而非Scala的Tuple。
三种解决方案
方案1:使用Java Map Entry实例匹配
直接创建java.util.Map.Entry对象来替代Scala Tuple,这样就能和Java Map中的元素类型匹配。如果是Java 8及以下版本,可使用AbstractMap.SimpleEntry;Java 9+则有更简洁的Map.entry静态方法:
import java.util.AbstractMap val testMap = new java.util.LinkedHashMap[Int, Int]() testMap.put(1,2) testMap.put(2,4) testMap.put(3,6) // Java 8及以下写法 testMap should contain allOf ( new AbstractMap.SimpleEntry(1,2), new AbstractMap.SimpleEntry(2,4), new AbstractMap.SimpleEntry(3,6) ) // Java 9+ 简洁写法(需导入java.util.Map) // import java.util.Map // testMap should contain allOf (Map.entry(1,2), Map.entry(2,4), Map.entry(3,6))
方案2:将Java Map转换为Scala Map
借助Scala的Java集合转换工具,把java.util.LinkedHashMap转换成Scala原生的Map,这样就能直接用Scala Tuple做断言了:
import scala.collection.JavaConverters._ val testMap = new java.util.LinkedHashMap[Int, Int]() testMap.put(1,2) testMap.put(2,4) testMap.put(3,6) // 转换为Scala Map后使用Tuple断言 testMap.asScala should contain allOf (1->2, 2->4, 3->6)
注:Scala 2.13+推荐用
scala.jdk.CollectionConverters替代JavaConverters,但你使用的Scala 2.11版本,JavaConverters是正确选择。
方案3:使用ScalaTest的allEntriesOf匹配器
ScalaTest提供了更贴合Map场景的匹配器allEntriesOf,可以直接传入一个Scala Map来断言Java Map包含所有对应键值对,这是最简洁的方案:
val testMap = new java.util.LinkedHashMap[Int, Int]() testMap.put(1,2) testMap.put(2,4) testMap.put(3,6) testMap should contain allEntriesOf Map(1->2, 2->4, 3->6)
内容的提问来源于stack exchange,提问作者Gabriel

