読者です 読者をやめる 読者になる 読者になる

成らぬは人の為さぬなりけり

エンジニアライフをエンジョイする為のブログ

Specs2でinを複数ネストさせる時は要注意

今回は、久々にScalaネタです。

今回のテーマ

Specs2での「in」のネスト


環境

本題

Specs2で単体テストを書いていて、
Rspecのcontextのノリで、場合分けを書きたいときがありまして。
「in」を複数ネストさせました。

書いたspecは以下のような感じです。

import org.specs2.mutable.Specification

class Hoge {
  def name(name:String = "hoge") = name
}
class HogeSpec extends Specification {
  "Hoge" should {
    "#name" in {
      "must equal to hoge" in { // ①
        new Hoge().name() must_== "hoge"
      }
      "when add parameter" in { // ②
        "must equal to parameter" in {
          new Hoge().name("foo") must_== "foo"
        }
      }
    }
  }
}

Rspecのcontextのような書き方をしたい時にこのような書き方が正しいのかどうかはわかりません。。。
※英語も間違ってるでしょう、、、多分、、、そこは本題ではないので、無視してください(汗
※Hogeクラスも特に意味はありません。

これをテストしてみます。

[info] HogeSpec
[info] 
[info] Hoge should
[info] + #name
[info]  
[info]  
[info] Total for specification HogeSpec
[info] Finished in 19 ms
[info] 1 example, 0 failure, 0 error
[info] 
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0
[success] Total time: 2 s, completed 2013/05/04 22:27:38

いろいろおかしいですね。

  • テストが1件(①のみ)しか実行されてない
  • しかも#nameまでしか書かれていない
  • 試しに①を「new Hoge().name() must_== "hogehoge"」にしてみても、グリーンになる

ふむ。困りました。

で、とりあえず、②を消して実行してみました。

class HogeSpec extends Specification {
  "Hoge" should {
    "#name" in {
      "must equal to hoge" in { // ①
        new Hoge().name() must_== "hoge"
      }
    }
  }
}

実行結果

[info] HogeSpec
[info] 
[info] Hoge should
[info]   #name
[info]   + must equal to hoge
[info]  
[info]  
[info]  
[info] Total for specification HogeSpec
[info] Finished in 28 ms
[info] 1 example, 0 failure, 0 error
[info] 
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0
[success] Total time: 3 s, completed 2013/05/04 22:30:21

ちゃんとの①が実行されてるっぽいです。
※試しに「new Hoge().name() must_== "hogehoge"」にするとちゃんとfailしました。

今度は、②のみで実行してみます。

class HogeSpec extends Specification {
  "Hoge" should {
    "#name" in {
      "when add parameter" in { // ②
        "must equal to parameter" in {
          new Hoge().name("foo") must_== "foo"
        }
      }
    }
  }
}
[info] HogeSpec
[info] 
[info] Hoge should
[info] + #name
[info]  
[info]  
[info] Total for specification HogeSpec
[info] Finished in 17 ms
[info] 1 example, 0 failure, 0 error
[info] 
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0
[success] Total time: 3 s, completed 2013/05/04 22:36:36

こちらは、最初と同じで、「#name」で止まってしまっているようです。

じゃあどうするのか?

原因はとりあえず、後で調べるとして、
ひとまず、どうすれば出来るのか。

specs2のドキュメントを読んでいると、、、
Structure


>>: create an Example or a group of Examples (with no appended text)

これっぽい。
試してみます。

class HogeSpec extends Specification {
  "Hoge" should {
    "#name" >> {
      "must equal to hoge" in { // ①
        new Hoge().name() must_== "hoge"
      }
      "when add parameter" in { // ②
        "must equal to parameter" in {
          new Hoge().name("foo") must_== "foo"
        }
      }
    }
  }
}
[info] HogeSpec
[info] 
[info] Hoge should
[info]   #name
[info]  
[info] + must equal to hoge
[info]   when add parameter
[info]   + must equal to parameter
[info]  
[info]  
[info]  
[info] Total for specification HogeSpec
[info] Finished in 31 ms
[info] 2 examples, 0 failure, 0 error
[info] 
[info] Passed: : Total 2, Failed 0, Errors 0, Passed 2, Skipped 0
[success] Total time: 3 s, completed 2013/05/04 22:51:39

なんかちょっと見た目はおかしいですが、両方実行されました。

exampleのグループを作る場合は「>>」を使いなさい、という事なんでしょうか?

では、こうすると、どうなるのか。

class HogeSpec extends Specification {
  "Hoge" should {
    "#name" in {
      "must equal to hoge" in { // ①
        new Hoge().name() must_== "hoge"
      }
//      "when add parameter" in { // ②
        "must equal to parameter" in {
          new Hoge().name("foo") must_== "foo"
        }
//      }
    }
  }
}
info] HogeSpec
[info] 
[info] Hoge should
[info]   #name
[info]   + must equal to hoge
[info]   + must equal to parameter
[info]  
[info]  
[info]  
[info] Total for specification HogeSpec
[info] Finished in 29 ms
[info] 2 examples, 0 failure, 0 error
[info] 
[info] Passed: : Total 2, Failed 0, Errors 0, Passed 2, Skipped 0
[success] Total time: 3 s, completed 2013/05/04 22:54:28

これは大丈夫。
んー、、、
では、階層が違うものが複数いるとダメなんでしょうか?
①も一個ネストさせてみます。

class HogeSpec extends Specification {
  "Hoge" should {
    "#name" in {
      "xxx" in {
        "must equal to hoge" in { // ①
          new Hoge().name() must_== "hoge"
        }
      }
      "when add parameter" in { // ②
        "must equal to parameter" in {
          new Hoge().name("foo") must_== "foo"
        }
      }
    }
  }
}
[info] HogeSpec
[info] 
[info] Hoge should
[info] + #name
[info]  
[info]  
[info] Total for specification HogeSpec
[info] Finished in 19 ms
[info] 1 example, 0 failure, 0 error
[info] 
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0
[success] Total time: 3 s, completed 2013/05/04 22:56:06

ダメでした。

まとめ

とりあえず、なんとかなったものの、、
結局Specs2に関して、全く知らないで使っていたんだと改めて反省しました。
Specs2のドキュメントを見ていると知らない機能がたんまりある、、、
これから、改めて、Specs2を勉強し直そうとおもいます。