ScalaTest - 编写自定义匹配器

问题描述:

我遇到了一个问题,同时写NodeSeq自定义匹配:ScalaTest - 编写自定义匹配器

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)) 

任何想法是什么意思?

+0

什么是NodeSeq的定义是什么? – 2013-05-02 15:44:12

+0

@MikaëlMayer我假设'scala.xml.NodeSeq' – gzm0 2013-05-02 15:49:47

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

类型检查工作以下面的方式。

xml.should(matchXML(expected)) 
  • 因为该方法should不是NodeSeq的一部分,该编译器试图找到一个xmlimplicit conversionShouldMatcher。 书“编程在斯卡拉”规定,这样的隐式转换应该是最具体:

“上通过的Scala 2.7,这是故事的结尾每当应用 多个隐式转换,编译器。拒绝在它们之间选择 ...... Scala 2.8放宽了这个规则如果其中一个可用的 转换比其他转换更严格,那么 编译器将选择更具体的转换......一个隐式转换 如果满足以下条件之一,则比另一个更具体:前者的参数类型为 后者的ubtype。 ..”

  • 因为NodeSeq延伸Seq[Node],下面的函数,因此

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

    是所有其他人之间最特殊的一个。

改写程序如:

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

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

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

因为T出现在箭头的左侧,匹配器不是covariantT,但是是逆变。A NodeSeqGenSeq[Node],所以Matcher[GenSeq[Node]]Matcher[NodeSeq],而不是相反。这解释了上述错误,其中方法should不能接受Matcher[NodeSeq]并且需要Matcher[GenSeq[Node]]

2解决方案

  • 替换的NodeSeq所有实例GenSeq[Node],这样的类型匹配随处可见。
  • 或者,用转换函数明确地包装xml。

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

+0

虽然第二种解决方案起作用,但第一种解决方案(将所有内容转换为“Seq [Node]”)仍显示相同的错误。 – HRJ 2013-08-11 14:46:22

+0

我可以通过将所有内容转换为GenSeq [Node]来解决这个问题。我正在使用'scalatest 2.0 M5',因此可能有所不同。 – HRJ 2013-08-11 14:50:21

+0

的确,在这个版本中,convertToSeqShouldWrapper方法的签名是'GenSeq [T] => SeqShouldWrapper [T]'。所以我更新了我的答案。 – 2013-08-12 09:23:05

这对我来说就像你的matchXML方法不在范围内。

+0

即使matchXML在范围内,我也得到了同样的错误。 – 2013-05-06 09:23:43