ScalaTest语法如何工作?

时间:2009-10-13 07:04:33

标签: syntax scala

我在Scala中做了一些编程,我知道,例如,

xs map f

相同
xs.map(f)

但我不知道如何将这种语法概括为像ScalaTest的语法,例如,

it should "throw NoSuchElementException if an empty stack is popped" in {
  val emptyStack = new Stack[String]
  evaluating { emptyStack.pop() } should produce [NoSuchElementException]
}

我主要想知道看起来像多字构造的东西,即should produce。它很整洁。

2 个答案:

答案 0 :(得分:11)

这种语法是运算符表示法中的方法调用,但不仅仅是三个令牌。如你所说:

xs map f

表示:

xs.map(f)

但你可以更进一步说:

xs map f map g

表示:

xs.map(f).map(g)

例如,在ScalaTest匹配器中,您可以说:

result should not be null

编译器对它感到害怕:

result.should(not).be(null)

此:

it should "throw an exception" in { ... }

变得卑鄙:

it.should("throw an exception").in { ... }

最后的花括号实际上只是将花括号(测试代码)之间的代码传递给in方法的一种方法,包装为无参数函数。所以这些都是同一个想法。运算符表示法连续两次使用。

你问到的最后一个有点不同:

evaluating { ... } should produce [IllegalArgumentException]

这变成了:

首先评估

evaluating { ... },因为花括号使它优先。这是一个方法调用,您正在调用一个名为“evaluate”的方法,将花括号之间的代码作为无参数函数传递。返回一个应该调用的对象。所以应该是通过调用求值返回的对象的方法。实际需要的是调用产品的结果。这里产生的实际上是一个方法,它有一个类型参数,如[IllegalArgumentException]。它必须以这种方式完成,因此Scala编译器可以“穷人 - 实现”该类型参数。它将隐式“Manifest”参数传递给可以为java.lang.Class提供IllegalArgumentException实例的产品。因此,当调用方法时,它有一个包含传递给求值的代码的函数,以及一种查找放在方括号中的异常类型的java.lang.Class的方法。因此它执行try中包含的代码块,捕获异常,将其与预期进行比较。如果没有抛出异常或错误的异常,则should方法抛出TestFailedException。否则,should方法只是静默返回。

所以,答案就是这条线被玷污了:

(evaluating { ... }).should(produce[IllegalArgumentException] (compilerSuppliedManifest))

故事的寓意是,像这样的高级代码使得更容易看到程序员的意图,但往往更难理解代码的实际工作方式。在实践中大部分时间你所关心的只是意图,但是你需要知道某些东西是如何工作的。在Scala中的这种情况下,您可以将-Xprint:typer作为命令行arg传递给Scala编译器,它将在所有desugaring发生后打印出您的文件版本。所以你可以在需要时看到什么。

答案 1 :(得分:2)

这很简单,因为它是正常的代码 - it should等同于it.should因此在范围内必须有一个名为it的值(或方法)。并there is

此变量的类型为ItWord,它公开了一个名为should的方法,它接受类型为BehaveWord的对象。这些匹配器通过ShouldMatchers trait中的隐式转换进行混合。

ScalaTest实际上记录极其,包含大量示例和对事物运作方式的描述。