ScalaTest - 编写自定义匹配器

时间:2013-05-02 15:24:39

标签: scala testing matcher scalatest

我在为NodeSeq编写自定义匹配器时遇到了问题:

private def matchXML(expected: NodeSeq) = new Matcher[NodeSeq] {
  def apply(left: NodeSeq): MatchResult = MatchResult(left xml_== expected,
    "XML structure was not the same (watch spaces in tag texts)",
    "XML messages were equal")
}

这编译,但下面的代码:

val expected : NodeSeq = ...
val xml : NodeSeq = ... 
xml should matchXML(expected)

导致:

error: overloaded method value should with alternatives:
(beWord: XMLStripDecoratorTests.this.BeWord)XMLStripDecoratorTests.this.ResultOfBeWordForAnyRef[scala.collection.GenSeq[scala.xml.Node]] <and>
(notWord: XMLStripDecoratorTests.this.NotWord)XMLStripDecoratorTests.this.ResultOfNotWordForAnyRef[scala.collection.GenSeq[scala.xml.Node]] <and>
(haveWord: XMLStripDecoratorTests.this.HaveWord)XMLStripDecoratorTests.this.ResultOfHaveWordForSeq[scala.xml.Node] <and>
(rightMatcher: org.scalatest.matchers.Matcher[scala.collection.GenSeq[scala.xml.Node]])Unit
cannot be applied to (org.scalatest.matchers.Matcher[scala.xml.NodeSeq])
xml should (matchXML(expected))

这意味着什么?

2 个答案:

答案 0 :(得分:8)

为什么不能进行类型检查:

类型检查器按以下方式工作。

xml.should(matchXML(expected))
  • 由于方法should不属于NodeSeq,因此编译器会尝试为xml ShouldMatcher找到implicit conversion。 “Scala编程”一书指出这种隐式转换应该是最具体的:
  

“通过Scala 2.7,这是故事的结尾。无论何时   应用了多个隐式转换,编译器拒绝选择   它们之间。 ...... Scala 2.8放松了这个规则。如果其中一个可用   转换比其他转换更严格,然后转换   编译器将选择更具体的一个。 ......一个隐含的转换   如果下列之一适用,则比其他更具体:   前者的参数类型是后者的子类型。 ..“

  • 由于NodeSeq扩展了Seq[Node],因此以下函数

    convertToSeqShouldWrapper[T](o : scala.GenSeq[T]) : SeqShouldWrapper[T]

    因此是所有其他人中最具体的一个。

该程序被重写为:

`convertToSeqShouldWrapper(xml).should(matchXML(expected))`

其中convertToSeqShouldWrapper(xml)SeqShouldWrapper[T] T = GenSeq[Node]

来自should的方法SeqShouldWrapper接受Matcher[T],它是T => MatchResult类型的函数。因此,它接受Matcher[GenSeq[Node]]

由于T出现在箭头的左侧,匹配器在T中不是covariant,而是逆变。 NodeSeqGenSeq[Node],因此Matcher[GenSeq[Node]]Matcher[NodeSeq],而不是相反。这解释了上述错误,方法should无法接受Matcher[NodeSeq]并且需要Matcher[GenSeq[Node]]

2解决方案

  • NodeSeq的所有实例替换为GenSeq[Node],以便类型与所有地方匹配。
  • 或者,使用转换函数明确地包装xml。

    convertToAnyShouldWrapper(xml).should(matchXML(expected))

答案 1 :(得分:-1)

我认为您的matchXML方法不在范围内。