Scala 如何测试异常
几年前整理过一篇 JUnit 4 如何正确测试异常,类似的问题:如何在 Scala 中测试异常呢?因 Scala 可以完全采用 JUnit 测试用例的风格,所以当然可以运用 Java 的三种方式来测试异常,即
回到 Scala 中来,我并不那么情愿在 Scala 中使用 JUnit 的 @Test def testMethod() 这样的测试方法风格,而多少采用 BDD 或者叫更 DSL 的风格。
那看看我们 Scala 有些什么独到的异常测试方法
一: intercept
测试结果
打开
intercept() 方法返回的是当前抛出的异常,所以可以对它的返回值进行更详细的断言
二:thrownBy
执行之后的描述信息是
也就是
thrownBy 的实现方式与 intercept 是一样的。
第一代 specs 可以用 throwA/throwAn 方法,现在转到 specs2 了,specs 已停止开发,从 https://code.google.com/p/specs/ 找了个例子:
Scala 使用 Java 的风格与 JUnit 4 如何正确测试异常 中的用法基本一致的。try-catch 方式也只是存在语法上的差异
总之,Scala 风格的异常测试也就是 intercept 和 thrownBy 两种。
参考:1. ScalaTest
2. specs 永久链接 https://yanbin.blog/scala-how-to-test-exception/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
- try { 待测试代码; fail() } catch(某种异常) {断言}
- @Test(expected = Exception.class)
- @Rule
回到 Scala 中来,我并不那么情愿在 Scala 中使用 JUnit 的 @Test def testMethod() 这样的测试方法风格,而多少采用 BDD 或者叫更 DSL 的风格。
那看看我们 Scala 有些什么独到的异常测试方法
一: intercept
1import org.scalatest.FlatSpec
2
3class ScalaExceptionTest extends FlatSpec {
4 "An empty Set" should "produce NoSuchElementException when head is invoked" in {
5 intercept[NoSuchElementException] {
6 Set.empty.head
7 }
8 }
9}测试结果
打开 intercept 方法的源码,其实这就是 try-catch 的方式。intercept 方法的源码如下: 1def intercept[T <: AnyRef](f: => Any)(implicit manifest: Manifest[T]): T = {
2 val clazz = manifest.erasure.asInstanceOf[Class[T]]
3 val caught = try {
4 f
5 None
6 }
7 catch {
8 case u: Throwable => {
9 if (!clazz.isAssignableFrom(u.getClass)) {
10 val s = Resources("wrongException", clazz.getName, u.getClass.getName)
11 throw newAssertionFailedException(Some(s), Some(u), 4)
12 }
13 else {
14 Some(u)
15 }
16 }
17 }
18 caught match {
19 case None =>
20 val message = Resources("exceptionExpected", clazz.getName)
21 throw newAssertionFailedException(Some(message), None, 4)
22 case Some(e) => e.asInstanceOf[T] // I know this cast will succeed, becuase isAssignableFrom succeeded above
23 }
24}intercept() 方法返回的是当前抛出的异常,所以可以对它的返回值进行更详细的断言
1val s = "hi"
2val thrown = intercept[IndexOutOfBoundsException] {
3 s.charAt(-1)
4}
5assert(thrown.getMessage === "String index out of range: -1")二:thrownBy
1import org.scalatest.{MustMatchers, WordSpec}
2
3class ScalaExceptionTest extends WordSpec with MustMatchers{
4
5 "An empty Set produce NoSuchElementException when head is invoked" in {
6 a[NoSuchElementException] must be thrownBy {
7 Set.empty.head
8 }
9 }
10}执行之后的描述信息是
1[info] ScalaExceptionTest:
2[info] - An empty Set produce NoSuchElementException when head is invoked
3[info] ScalaTest
4[info] Run completed in 1 second, 247 milliseconds.
5[info] Total number of tests run: 1
6[info] Suites: completed 1, aborted 0
7[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
8[info] All tests passed.也就是
in {} 中的执行代码从描述信息并没有帮助,虽然它看上去很美。thrownBy 的实现方式与 intercept 是一样的。
第一代 specs 可以用 throwA/throwAn 方法,现在转到 specs2 了,specs 已停止开发,从 https://code.google.com/p/specs/ 找了个例子:
1"A full stack"->-(fullStack) should {
2 behave like "A non-empty stack below full capacity"
3 "throw an exception when sent #push" in {
4 stack.push(11) must throwAn[Error]
5 }
6}Scala 使用 Java 的风格与 JUnit 4 如何正确测试异常 中的用法基本一致的。try-catch 方式也只是存在语法上的差异
1import org.junit.Assert._
2import org.junit.Test
3
4class ScalaExceptionTest{
5
6 @Test def testInvokeHeadOnEmptySet: Unit = {
7 try {
8 Set.empty.head
9 fail("nothing thrown")
10 } catch {
11 case err: NoSuchElementException => // test success
12 case t: Throwable => fail(s"caught ${t.getClass.getName} instead of NoSuchElementException")
13 }
14 }
15}总之,Scala 风格的异常测试也就是 intercept 和 thrownBy 两种。
参考:1. ScalaTest
2. specs 永久链接 https://yanbin.blog/scala-how-to-test-exception/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。