一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Scala学习笔记之测试异常

时间:2015-09-03 编辑:简简单单 来源:一聚教程网

年前整理过一篇 JUnit 4 如何正确测试异常,类似的问题:如何在 Scala 中测试异常呢?因 Scala 可以完全采用 JUnit 测试用例的风格,所以当然可以运用 Java 的三种方式来测试异常,即

try { 待测试代码; fail() } catch(某种异常) {断言}

@

Test(expected = Exception.class)

@Rule

回到 Scala 中来,我并不那么情愿在 Scala 中使用 JUnit 的 @Test def testMethod() 这样的测试方法风格,而多少采用 BDD 或者叫更 DSL 的风格。

那看看我们 Scala 有些什么独到的异常测试方法

一: intercept

import org.scalatest.FlatSpec
 
class ScalaExceptionTest extends FlatSpec {
  "An empty Set" should "produce NoSuchElementException when head is invoked" in {
    intercept[NoSuchElementException] {
      Set.empty.head
    }
  }
}
测试结果
scala-intercept

打开 intercept 方法的源码,其实这就是 try-catch 的方式。intercept 方法的源码如下:

def intercept[T <: AnyRef](f: => Any)(implicit manifest: Manifest[T]): T = {
    val clazz = manifest.erasure.asInstanceOf[Class[T]]
    val caught = try {
      f
      None
    }
    catch {
      case u: Throwable => {
        if (!clazz.isAssignableFrom(u.getClass)) {
          val s = Resources("wrongException", clazz.getName, u.getClass.getName)
          throw newAssertionFailedException(Some(s), Some(u), 4)
        }
        else {
          Some(u)
        }
      }
    }
    caught match {
      case None =>
        val message = Resources("exceptionExpected", clazz.getName)
        throw newAssertionFailedException(Some(message), None, 4)
      case Some(e) => e.asInstanceOf[T] // I know this cast will succeed, becuase isAssignableFrom succeeded above
    }
  }
intercept() 方法返回的是当前抛出的异常,所以可以对它的返回值进行更详细的断言
val s = "hi"
val thrown = intercept[IndexOutOfBoundsException] {
  s.charAt(-1)
}
assert(thrown.getMessage === "String index out of range: -1")

二:thrownBy

import org.scalatest.{MustMatchers, WordSpec}
 
class ScalaExceptionTest extends WordSpec with MustMatchers{
 
  "An empty Set produce NoSuchElementException when head is invoked" in {
    a[NoSuchElementException] must be thrownBy {
      Set.empty.head
    }
  }
}

执行之后的描述信息是
[info] ScalaExceptionTest:
[info] - An empty Set produce NoSuchElementException when head is invoked
[info] ScalaTest
[info] Run completed in 1 second, 247 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.


也就是 in {} 中的执行代码从描述信息并没有帮助,虽然它看上去很美。

thrownBy 的实现方式与 intercept 是一样的。

第一代 specs 可以用 throwA/throwAn 方法,现在转到  specs2 了,specs 已停止开发,从 https://code.google.com/p/specs/ 找了个例子:

"A full stack"->-(fullStack) should {

  behave like "A non-empty stack below full capacity"

  "throw an exception when sent #push" in {

    stack.push(11) must throwAn[Error]

  }

}

Scala 使用 Java 的风格与 JUnit 4 如何正确测试异常 中的用法基本一致的。try-catch 方式也只是存在语法上的差异

import org.junit.Assert._

import org.junit.Test

 

class ScalaExceptionTest{

 

  @Test def testInvokeHeadOnEmptySet: Unit = {

    try {

      Set.empty.head

      fail("nothing thrown")

    } catch {

      case err: NoSuchElementException => // test success

      case t: Throwable => fail(s"caught ${t.getClass.getName} instead of NoSuchElementException")

    }

  }

}


总之,Scala 风格的异常测试也就是 intercept 和 thrownBy 两种。

热门栏目