12.6 异常测试
异常测试用来确保被测的代码单元可以抛出预期的异常。
下面是个异常测试的例子:
def testGetOnEmptyList() {
try {
val list = new java.util.ArrayList[Integer]
list.get(0)
fail("Expected exception for getting element from empty list")
}
catch {
case ex: IndexOutOfBoundsException => // :) Success
}
}
java.util.ArrayList
的实例被创建之后,我们会得到一个空的列表。在测试里,我们尝试获取列表中并不存在的第一个元素,期望这个操作可以抛出IndexOutOfBoundsException
异常。如果get()
方法抛出了该异常或是它的子类,catch
⑦就会捕获到,这个过程就表示代码的行为和我们的期望一致。如果方法抛出了其他异常,那么这些异常就不会被捕获,测试就会失败。另外,如果方法没有抛出异常,测试就会执行到fail()
方法,同样会失败。我管它叫地雷方法,因为踩上就会爆炸。
⑦Scala的
try-catch-finally
语义跟Java的一样,但catch
语法不尽相同——它用的是模式匹配语法(参见第9章,“模式匹配和正则表达式”)。
上面这个异常测试完成了它的任务,可是也太啰唆了点。而且如果你忘了调用fail()
方法的话,它甚至也不会给你提醒。它如果更简洁⑧一些该多好。这时候就可以用到ScalaTest的intercept()
方法了。使用intercept()
方法会让上面的异常测试清晰许多:
⑧请见我的博客“Prefer Conciseness over Terseness”。地址是http://tinyurl.com/5bawat。
def testGetOnEmptyList_Concise() {
val list = new java.util.ArrayList[Integer]
intercept(classOf[IndexOutOfBoundsException],
"Expected exception for getting element from empty list"){
list.get(0)
}
//上面的语句会有“已废弃”的警告。ScalaTest在不断完善中,
即将采用新风格的intercept。
//当前的新风格还没有使用错误信息变量,等它完成以后,你就该这样用了:
//intercept[IndexOutOfBoundsException] ("Expected ...") {...}⑨
}
⑨ScalaTest 1.0就是这样用的。——译者注
intercept()
方法会接收一个异常类作为参数、一个可选的错误消息、一个闭包,闭包里是会抛出给定异常的表达式。如果表达式抛出了预期的异常或是它的子类,intercept()
方法就会捕获这个异常,并把它返回——如果需要的话,可以使用这个结果,它还可以检查具体的异常信息。如果表达式没有抛出任何异常,或是抛出了一个不该抛出的异常,intercept()
方法就会失败。