ScalaTest - 编写自定义匹配器

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

知道这是什么意思吗?

最佳答案

为什么无法进行类型检查:

类型检查器的工作方式如下。

xml.should(matchXML(expected))
  • 因为方法 should不是 NodeSeq 的一部分,编译器试图找到一个 implicit conversion对于 xmlShouldMatcher . 《Programming in Scala》一书规定,这种隐式转换应该是最具体的:

"Up through Scala 2.7, that was the end of the story. Whenever multiple implicit conversions applied, the compiler refused to choose between them. ... Scala 2.8 loosens this rule. If one of the available conversions is strictly more specific than the others, then the compiler will choose the more specific one. ... one implicit conversion is more specific than another if one of the following applies: The argument type of the former is a subtype of the latter’s. .."

  • 因为 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出现在箭头的左侧,匹配器不是 covariantT , 但逆变。 NodeSeqGenSeq[Node] , 所以 Matcher[GenSeq[Node]]Matcher[NodeSeq] ,而不是相反。这解释了上面的错误,其中方法 should不能接受 Matcher[NodeSeq]并且需要 Matcher[GenSeq[Node]] .

2 种解决方案

  • 替换 NodeSeq 的所有实例至 GenSeq[Node]以便类型在任何地方都匹配。
  • 或者,使用转换函数显式包装 xml。

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

关于ScalaTest - 编写自定义匹配器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16341868/

相关文章:

scala - 使用 Scala 3 玩框架

java - 在长 Scala 列表或 Stream 上进行 reduce() 操作期间,Java JVM 关于 GC 的智能程度如何?

scala - 反编译 Scala 代码 : why there are two overridden methods in the derived class?

java - 匹配器的问题

android - Uri 匹配器与 uri 不匹配

arrays - Scala案例类参数从数组实例化

javascript - 将测试文件放在与源文件相同的文件夹中或单独放在 test/下的优缺点

android - Android 中的性能测试用例接口(interface)

PHPUnit模拟抽象类的所有方法

java - 匹配器以避免以 s、ing 结尾的单词或中间的单词