如何匹配抛出的Exception消息?

时间:2014-01-09 20:06:01

标签: scala specs2

The specs2 Matchers guide州:

  

throwA[ExceptionType](message = "boom")另外检查是否   异常消息是预期的

但是当我使用它时,消息显然在整个堆栈跟踪上匹配,而不仅仅是异常消息。

测试

"cont'd what if -- running test again shows that the app has already died" in {
  running(new FakeApplication(additionalConfiguration = inLocalPostgresDatabase())) {
    db2 withSession {
      val comboboxOpsClass = new ComboboxOps(database)
    }
  } must throwA[SQLException](message = "Attempting to obtain a connection from a pool that has already been shutdown")
}

堆栈跟踪

[error]      'Attempting to obtain a connection from a pool that has already been shutdown. 
[error]      Stack trace of location where pool was shutdown follows:
[error]       java.lang.Thread.getStackTrace(Thread.java:1568)
[error]       com.jolbox.bonecp.BoneCP.captureStackTrace(BoneCP.java:572)
[error]       com.jolbox.bonecp.BoneCP.shutdown(BoneCP.java:161)

许多行

[error]       org.specs2.execute.ResultExecution$class.execute(ResultExecution.scala:22)
[error]       org.specs2.execute.ResultExecution$.execute(ResultExecution.scala:116)
[error]       org.specs2.specification.FragmentExecution$class.executeBody(FragmentExecution.scala:28)
[error]       
[error]       sbt.ForkMain$Run.runTestSafe(ForkMain.java:211)
[error]       sbt.ForkMain$Run.runTests(ForkMain.java:187)
[error]       sbt.ForkMain$Run.run(ForkMain.java:251)
[error]       sbt.ForkMain.main(ForkMain.java:97)
[error]      ' doesn't match '.*Attempting to obtain a connection from a pool that has already been shutdown.*' (FakeApplicationSpec.scala:138)

有人能指出我对specs2的这种用法的一个有效例子吗?

3 个答案:

答案 0 :(得分:6)

我不想这么说但是我从来没有找到一种通用的方法来发现文本是什么,而不是让它发生并在事后添加...或者转到异常的来源并从那里复制它。这是我在Novus-JDBC第91行所做的:

"handle when take more than it can give" in{
  val iter0 = nonCounter()

  val iter = iter0 slice (0,10)

  (iter next () must be greaterThan 0) and
  (iter next () must be greaterThan 0) and
  (iter next () must be equalTo -1) and
  (iter next () must be equalTo 3) and
    (iter.hasNext must beFalse) and
    (iter next() must throwA(new NoSuchElementException("next on empty iterator")))
}

答案 1 :(得分:1)

如果将异常实现为案例类并在第一个构造函数参数列表中包含该消息,则可以选择匹配异常消息。

case class ObjectionException(statement: String)
extends    Exception(statement)

try throw ObjectionException("I object")
catch {
  case ObjectionException("I object")   => println("I objected to myself?")
  case ObjectionException("You object") => println("I don't care!")
  case ObjectionException(objection)    => println(s"Objection: $objection")
}

// Exiting paste mode, now interpreting.

I objected to myself?
defined class ObjectionException

scala>

您还可以使用Regex来匹配邮件:

val ContentObjection = ".*Content.*".r

try throw ObjectionException("ObjectionableContent")
catch {
  case ObjectionException(ContentObjection()) => println("Questionable Content")
  case ObjectionException(objection)          => println(s"Objection: $objection")
}

// Exiting paste mode, now interpreting.

Questionable Content
ContentObjection: scala.util.matching.Regex = .*Content.*

答案 2 :(得分:0)

框架将堆栈跟踪“捕获”作为字符串消息,而不是仅仅将异常填入某处并稍后抛出。

测试装备正在寻找s".*$message.*".r,如果没有DOTALL模式(这会使“点”与换行符匹配,也称为单行模式),这将无效:

scala> val text = """abc
     | def
     | ghi
     | jkl"""
text: String =
abc
def
ghi
jkl

scala> val r = ".*def.*".r
r: scala.util.matching.Regex = .*def.*

scala> import PartialFunction._
import PartialFunction._

scala> cond(text) { case r() => true }
res0: Boolean = false

scala> val r2 = "(?s).*def.*".r
r2: scala.util.matching.Regex = (?s).*def.*

scala> cond(text) { case r2() => true }
res1: Boolean = true

如果您只是测试文字的前缀,可以通过附加内联DOTALL (?s)来实现,即message = "boom(?s)"

scala> val r3 = ".*abc(?s).*".r
r3: scala.util.matching.Regex = .*abc(?s).*

scala> cond(text) { case r3() => true }
res2: Boolean = true

但是尝试在后续行上测试任何内容都将失败:

scala> val r4 = ".*(?s)def.*".r
r4: scala.util.matching.Regex = .*(?s)def.*

scala> cond(text) { case r4() => true }
res3: Boolean = false

如果测试框架那样做,那么锚定aweigh会起作用:

scala> val r5 = ".*def.*".r.unanchored
r5: scala.util.matching.UnanchoredRegex = .*def.*

scala> cond(text) { case r5() => true }
res4: Boolean = true