Specs2を試す(4)

参考: http://etorreborre.github.com/specs2/guide/org.specs2.guide.SpecStructure.html#Declare+examples

Result

// コード1
  "this is my specification"                          ^
    "and example 1"                                   ! e1^
    "and example 2"                                   ! e2

  def e1 = success
  def e2 = success

上の例の

    "and example 1"                                   ! e1^

この部分は、description ! body という形になっていて、
bodyの部分は Result(org.specs2.executable.Result) を返す。


このResultには3つのタイプがあって、それは

  • a standard result
  • a Matcher result
  • a boolean value

Standard results

これは一番単純なResultの値。StandardResultsトレイトによって提供されている。

ソースを見ればああなるほどってなる。

// コード2: specs2/src/main/scala/org/specs2/execute/StandardResults.scala
package org.specs2
package execute

/**
 * This trait provides standard results which can be used in Fragments bodies
 */
trait StandardResults {
  def done = Success("DONE")
  def wontdo = Success("WONT DO")
  def todo = Pending("TODO")
  def pending = Pending("PENDING")
  def anError = Error("error")
  def success = Success("success")
  def failure = Failure("failure")
  def skipped = Skipped("skipped")
}
object StandardResults extends StandardResults

例えばすでにsuccessとか使ってたけどこれは実はResultのサブクラスのSuccessクラスのインスタンスを返していたわけだ。


Matcher results

例えばこんなの

1 must_== 1


こいつはほかにも大量にある。

  • Matchers for Any
  • Option / Either matchers
  • String matchers
  • Numeric matchers
  • Exception matchers
  • Iterable matchers
  • Map matchers
  • Xml matchers
  • Json matchers
  • File matchers
  • Scalaz matchers
  • Result matchers
  • Interpreter matchers
  • Parsers matchers

いろいろありすぎてめんどいので細かく見ていくのはまた今度ということで。

Functional expectations

specs2っていうかScalaは関数の中で評価された最後の式が返り値になる。
だから次のようなことが起こる。

// コード3
  "my example on strings" ! e1                // 結果はsuccess

  def e1 = {
    "hello" must have size(10000)             // <- ここの結果は返らない!!
    "hello" must startWith("hell")            // <- ここの結果が返る
  }

これを防ぐには例えば次のように and を使う。

// コード4
  "my example on strings" ! e1               // 結果はfailure

  def e1 = "hello" must have size(10000) and
                        startWith("hell")

Thrown Expectations

コード4 のような書き方のほかに org.specs2.matcher.MustThrownMatchers トレイトを使えば、
1つ目の式が失敗した時点で FailureException を飛ばして終了させることができる。
こんな風に使う。


// コード5
  "my example on strings" ! e1                // 結果はFailure

  def e1 = new Scope extends MustThrownMatchers {
    "hello" must have size(10000)             // <- ここで FailureException が飛ぶ
    "hello" must startWith("hell")            // <- ここはスルー
  }


それから FailureException を飛ばす failure(message) っていうメソッドもある。

// コード6
  "my example on strings" ! e1                // 結果はFailure

  def e1 = new Scope extends MustThrownMatchers {
    failure("うつだしのう...")                 // <- ここで FailureException が飛ぶ
    "hello" must startWith("hell")            // <- ここはスルー
  }


org.specs2.specification.Scope は trait で Success に暗黙変換される。そんな便利なやつ。