2012-12-13
GroovyでJUnitなテストを書くときの注意点……なんて無かった #gadvent2012
Groovy!!(挨拶)
G* Advent Calendar 2012 の13日目でございます。
- 前日: SpockでビルトインされているExtensionsとかそのへん - Yamkazu's Blog / @yamkazuさん
- 翌日:
groovy.lang.MissingPropertyException*1*2
JUnitをGroovyで使うなど
何も考えずに突っ込みどころ満載のFizzBuzzとテスト(色々足りてない)を書きます。
これをGroovyで書くとします。
- HogeGroovyTest.groovy(ほぼ HogeJavaTest.java のまま)
そのままJUnitとして動きます。Eclipse と IntelliJ IDEA では動くの確認できてます。
まんまコピペで何も嬉しくないので、Groovyらしくセミコロンを消したり、要らない括弧も消しましょう。
assertThat(sut.fizzBuzz(3), is("Fizz")); // Java assertThat sut.fizzBuzz(3), is("Fizz") // Groovy!!
素晴らしい!みんなGroovyやりたくなったね!
……んなバカな。
プロダクトコードをJavaで書いてテストをGroovyで書くアプローチはとても有効だと思ってるんですが、先に挙げたようなところで止まると微妙。いや止まらないとは思うのですが。
JUnitをそのまま使えるので、それなりのJUnit力が有れば特に問題は無いと思います。とは言っても、「何か使えなかったり、ハマる所有るんじゃないの?」とか心配する気持ちもわかります。わかりませんけどわかることにします。なので一通りやってハマりどころを書こうと思いました。
……すんなり出来すぎて*3何も出て来なかった。あえて言うなら「中途半端にGroovyにかぶれてると困るかもしれない」とか。以下はそんなメモです。
JUnitに関わるあれそれ
ごくごく普通に @RunWith とか @Rule とかも使えます。
RunWith がちょっとシンプルに書ける
ちょっとだけね。
@RunWith(Enclosed.class) // Java @RunWith(Enclosed) // Groovy
Rule はちゃんと書かないと怒られる
@Rule public TestRule watcher = new TestWatcher() { @Override protected void starting(Description description) { println description.methodName } }
折角Groovy使ってるんだから、色々と手を抜きたいと思うものです。でも上記コードの public TestRule を def とか書いたらダメーって言われる。JUnitのエラーメッセージは親切なので、こけたらわかるんですが、一応書いておきます。
JUnitが気にしてるのは @Rule がついてるフィールドが public な TestRule であることでしかないので、そこに何を入れるかは好きにして構いません。なので、上記コードはこんなふうに書くことも出来ます。誰得。
@Rule public TestRule watcher = [starting: { println it.methodName }] as TestWatcher
Thories もすんなり
@RunWith(Theories) static class TheoriesTest { HogeGroovy sut = new HogeGroovy() @DataPoints static Object[] params() { def map = [:] map << [3: "Fizz", 12: "Fizz"] map << [5: "Buzz", 10: "Buzz"] map << [15: "FizzBuzz", 30: "FizzBuzz"] } @Theory public void test(def param) { assert sut.fizzBuzz(param.key) == param.value } }
あえて言うならば @Datapoints の型は配列でなきゃヤダーと言われるところですかね。めんどくさいんで Object[] にしちゃってますが、害は無いでしょう。あまり意識してなかったのですが、ここでは map が Object[] に強制型変換食らって Entry 各々の配列になってたりします。動いてびっくりした……。
Spockを混ぜ込む
ここまで来たら、みんな大好き Spock を混ぜ込みましょう。おもむろにEnclosedランナーのクラスにネストさせるだけです。
@RunWith(Enclosed) class HogeGroovyTest { // ...略... static class HogeSpock extends Specification { def "Enclosedの中でSpockが使えるよー"() { expect: true } } }
嬉しいですね。とても嬉しいですね。こういうことが出来るのも、SpockがJUnitだから……Spockを使うときに継承する Specification が @RunWith(Sputnik.class) が付けられたクラスだったりするんです。つまりSpockは元々JUnitなので、JUnitと混ぜて自然に実行できても何ら不思議ではないんです。
Spockが使える状況下でJUnitを使うのかは正直わかりませんが、それぞれ良さがあると思うんですよ。なのでその気になればこんな風に書けるってのは、場合によっては便利。かも。JUnitなのでSpockにもRuleが使えたりします。有効な場面には今の所遭遇したことないですが。
- 85 https://www.google.co.jp/
- 53 http://atnd.org/events/34317
- 14 http://t.co/eme5gxl0
- 9 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0CD0QFjAB&url=http://d.hatena.ne.jp/irof/20121213/p1&ei=0xMiUcPHIMTvlAWl1oGgCw&usg=AFQjCNGoMnJN2JUz3YEBJ3V0PHam9I7SVg&bvm=bv.42553238,d.dGI
- 8 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=0CDwQFjAC&url=http://d.hatena.ne.jp/irof/20121213/p1&ei=CiPQUKTuBKeSiQfj24CgBA&usg=AFQjCNGoMnJN2JUz3YEBJ3V0PHam9I7SVg&bvm=bv.1355534169,d.aGc
- 8 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0CFEQFjAD&url=http://d.hatena.ne.jp/irof/20121213/p1&ei=VQzRUP7DH9DAmQWJh4CADA&usg=AFQjCNGoMnJN2JUz3YEBJ3V0PHam9I7SVg&bvm=bv.1355534169,d.dGY
- 8 https://www.google.com/
- 7 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CDUQFjAA&url=http://d.hatena.ne.jp/irof/20121213/p1&ei=YTDPUN6zG8TPmAWdq4HwAw&usg=AFQjCNGoMnJN2JUz3YEBJ3V0PHam9I7SVg&sig2=1km492elycAUiEBVPowjCA&bvm=bv.1355325884,d.dGY
- 6 http://nscom.ns-sol.co.jp/co4/app/main/select?pageId=41346
- 6 http://piyopiyoducky.net/gadvent2012/
