ScalaTest在任何风格特征中都默认使用三个断言。您可以使用:
assert
一般断言assertResult
将预期与实际值区分开来;assertThrows
以确保一些代码抛出预期的异常。要在ScalaTest中快速移动,请学习并使用这三个断言。后来如果你喜欢你可以切换到更具表现力的匹配DSL。
ScalaTest的断言定义在特质上Assertions
,延伸Suite
到所有的风格特征。特色Assertions
也提供:
assume
有条件地取消测试;fail
无条件失败;cancel
无条件取消测试;succeed
无条件地测试成功;intercept
确保一些代码抛出一个预期的异常,然后对该异常进行断言;assertDoesNotCompile
确保一点代码不编译;assertCompiles
确保一些代码确实编译;assertTypeError
确保一些代码不能编译,因为一个类型(不解析)的错误;withClue
添加有关失败的更多信息。所有这些构造如下所述。
assert
宏在任何Scala程序中,您可以通过调用assert
和传递Boolean
表达式来编写断言,例如:
val left = 2 val right = 1 assert(left == right)
如果传递的表达式是true
,assert
将正常返回。如果false
,Scala assert
将会突然完成AssertionError
。此行为由assert
对象中定义的方法提供Predef
,其成员隐式导入到每个Scala源文件中。这个Assertions
特征定义了另assert
一种隐藏该属性的方法Predef
。它的行为是一样的,除非false
是通过它抛出 TestFailedException
而不是AssertionError
。为什么?因为不同的是AssertionError
,TestFailedException
携带关于堆栈跟踪中的哪个项目的信息表示失败的测试代码行,这可以帮助用户在失败的测试中更快速地找到违规代码行。此外,ScalaTest assert
提供比Scala更好的错误消息assert
如果您通过以前的Boolean
表达,left == right
以assert
在ScalaTest试验,失败会报,由于assert
目前作为宏来实现,包括报告的左边和右边的值。例如,给出与上述相同的代码,但使用ScalaTest断言:
import org.scalatest.Assertions._ val left = 2 val right = 1 assert(left == right)
TestFailedException
从此抛出的详细信息assert
将是:“2不等于1”。
ScalaTest的assert
宏通过识别传递给的表达式的AST中的模式assert
,对于一组有限的常见表达式,给出等效的ScalaTest匹配器表达式给出的错误消息。这里有一些例子,哪里a
是1,b
是2,c
是3,d
是4,xs
是List(a, b, c)
,num
是1.0:
assert(a == b || c> = d) //错误消息:1不等于2,3不大于或等于4 assert(xs.exists(_ == 4)) //错误消息:列表(1,2,3)不包含4 assert(“hello” .startsWith(“h”)&& “goodbye”.endsWith(“y”)) //错误消息:“hello”以“h”开头,但“再见”并没有以“y”结尾 assert(num.isInstanceOf [ Int ]) //错误消息:1.0不是scala.Int的实例 assert(Some(2).isEmpty) //错误消息:Some(2)不为空
对于无法识别的表达式,宏当前会打印出一个字符串表示形式(已完成)AST并添加"was false"
。以下是无法识别的表达式的错误消息的一些示例:
assert(None.isDefined) //错误消息:scala.None.isDefined为false assert(xs.exists(i => i> 10)) //错误消息:xs.exists(((i:Int)=> i。>(10)))was false
String
一个第二个参数来增加标准错误消息
assert
,如下所示:
val attempted = 2 assert(attempted == 1, "Execution was attempted " + left + " times instead of 1 time")
assert
,故障报告将更具体到您的问题域,从而帮助您调试问题。这种
Assertions
特征也混合在一起
TripleEquals
,它为您提供了一个
===
操作员,允许您
Equality
使用数字进行自定义,执行等式检查
Tolerance
,并在编译时使用兄弟特征强制实施类型约束
TypeCheckedTripleEquals
。
尽管assert
宏提供了一种自然可读的Scala assert
机制的扩展,它提供了良好的错误消息,但由于操作数变长,所以代码变得不太可读。此外,生成的错误消息==
和===
比较不区分实际值和预期值。操作数是刚刚打电话left
和right
,因为如果一个被命名expected
和其他actual
,这将是难以让人记住哪个是哪个。为了帮助这些断言的限制,Suite
包括一个assertResult
可以用来替代的方法assert
。要使用assertResult
,请将预期值放在括号中assertResult
,然后是包含应该导致预期值的代码的花括号。
val a = 5 val b = 2 assertResult(2){ a - b }
在这种情况下,期望值为2
,正在测试的代码为a - b
。该断言将失败,并且详细信息TestFailedException
将显示为“Expected 2, but got 3"。
如果您只需要测试失败,您可以写:
fail("I've got a bad feeling about this")
或者
fail()
在异步式的测试,你必须以结束考试的身体Future[Assertion]
或 Assertion
。ScalaTest的断言(包括匹配器表达式)具有结果类型 Assertion
,因此以断言结尾将满足编译器。如果传递给人体试验或函数体Future.map
也 不会与类型结束Assertion
,但是,您可以通过将固定类型的错误 succeed
在测试或函数体的结尾:
succeed // Has type Assertion
有时,您需要测试一些方法是否会在某些情况下抛出预期的异常,例如,当无效参数传递给该方法时。您可以在JUnit 3样式中执行此操作,如下所示:
val s = "hi" try { s.charAt(-1) fail() } catch { case _: IndexOutOfBoundsException => // Expected, so continue }
如果按预期的方式charAt
投掷IndexOutOfBoundsException
,控制将转移到捕获情况,这不会做任何事情。但是,如果charAt
无法抛出异常fail()
,则会运行下一条语句。该fail
方法总是以a突然完成TestFailedException
,从而发出失败的测试信号。
为了使这种常见的情况更容易表达和阅读,ScalaTest提供了两种方法: assertThrows
和intercept
。以下是您使用的方式assertThrows
:
val s = “hi” assertThrows [ IndexOutOfBoundsException ] { //结果类型:Assertion s.charAt( - 1) }
此代码的行为与上一个例子非常相似。如果charAt
抛出一个实例IndexOutOfBoundsException
, assertThrows
将返回Succeeded
。但是如果charAt
正常完成,或者抛出一个异常,assertThrows
将会突然出现TestFailedException
。
该intercept
方法的行为相同assertThrows
,除了不是返回Succeeded
, intercept
返回捕获的异常,以便您可以进一步检查它。例如,您可能需要确保异常中包含的数据具有预期值。以下是一个例子:
val s = “hi” val catch = intercept [ IndexOutOfBoundsException ] { //结果类型:IndexOutOfBoundsException s.charAt( - 1) } assert(capture.getMessage.indexOf(“ - 1 ”)!= - 1)
通常,当创建库时,您可能希望确保代表潜在的“用户错误”的代码的某些安排不会编译,以使您的库具有更高的抗错误性。ScalaTest的Assertions
特征包括以下用于此目的的语法:
assertDoesNotCompile(“val a:String = 1”)
如果要确保代码段由于类型错误(而不是语法错误)而无法编译,请使用:
assertTypeError(“val a:String = 1”)
请注意,assertTypeError
如果给定的代码段由于类型错误而无法编译,则调用将成功。一个语法错误仍将导致抛出TestFailedException
。
如果你想指出的一小段代码并编译,你就可以说具有更明显:
assertCompiles(“val a:Int = 1”)
虽然以前的三个构造是用编译时确定的,由字符串表示的代码段是否被编译的宏来实现的,但错误在运行时被报告为测试失败。
Trait Assertions
还提供允许您取消测试的方法。如果测试所需的资源不可用,您将取消测试。例如,如果测试需要外部数据库联机,而不是,则可以取消测试以指示由于缺少数据库而无法运行该测试。这样的测试假设数据库是可用的,您可以使用该assume
方法在测试开始时指示这一点,如下所示:
assume(database.isAvailable)
assert
方法,trait
Assertions
提供了一个
assume
具有相同签名和行为的重载方法,除了
assume
方法throw,
TestCanceledException
而
assert
方法抛出
TestFailedException
。与之一样
assert
,
assume
隐藏Scala方法
Predef
,执行类似的功能,但抛出
AssertionError
。就像你可以一样
assert
,你会收到从传递给AST的宏提取的错误消息
assume
,并且可以可选地提供一个线索字符串来增加这个错误消息。这里有些例子:
assume(database.isAvailable, "The database was down again") assume(database.getAllUsers.count === 9)
对于每个重载fail
方法,有cancel
一个相同的方法具有相同的签名和行为,除了cancel
方法throw, TestCanceledException
而fail
方法抛出 TestFailedException
。因此,如果您只需要取消测试,您可以写:
cancel()
cancel("Can't run the test because no internet connection was found")
如果您希望通过方法默认提供更多信息,如果此特征,您可以通过多种方式之一提供“线索”字符串。您提供的额外信息(或“线索”)将包含在抛出的异常的详细消息中。双方 assert
并assertResult
提供直接包含线索的方式,intercept
其实不然。以下是直接提供的线索示例assert
:
assert(1 + 1 === 3, "this is a clue")
assertResult
:assertResult(3, "this is a clue") { 1 + 1 }
"this is a clue"
异常详细消息中的线索字符串。要获得与失败assertThrows
呼叫抛出的异常的详细消息相同的线索,请使用以下命令withClue
:withClue("this is a clue") { assertThrows[IndexOutOfBoundsException] { "hi".charAt(-1) } }
withClue
方法只会将线索字符串添加到混合在ModifiableMessage
特征中的异常类型的详细消息。有关ModifiableMessage
详细信息,请参阅文档。如果您希望在一段代码之后放置一个线索字符串,请参阅文档 AppendedClues
。