任意の条件でテストをスキップする

Spock にも JUnit4 の assumeThat のように ある条件の時だけ テストをスキップする機能が 0.5-groovy-1.8 で追加されています。
前回 のようにわざわざ設定を変更する必要がないので、環境に依存したテスト等には非常に便利です。

例えば、実行環境が Windows 以外の時だけ処理をスキップする (Windows のときだけ処理する) 場合は

package com.bluepapa32;

import spock.lang.*;

class HelloSpec extends Specification {

    @IgnoreIf({ properties['os.name'] !=~ /Windows.*/ })
    def 'Windows の場合 ○○する'() {
        expect: true
    }
}
のように フィーチャーメソッドに @IgnoreIf を付けます。
@IgnoreIf の引数には 真偽値を返すクロージャを渡します。
クロージャが true を返した場合、処理をスキップします。
このクロージャ内では静的変数、静的メソッド もしくは 次の暗黙オブジェクトだけが使えます。
変数名
properties System プロパティ
env 環境変数
javaVersion Java バージョン
残念ながら Specification のフィールドは参照できないようです。

この @IgnoreIf は Annotation Driven Extensions という Spock の拡張機能を使って実現されているようです。
Annotation Driven Extensions は アノテーションを付けることで AOP のように処理を追加する機能です。
Junit の Rule に少し似ていますが、Rule よりも もう少し高機能なようです。まだ、ちゃんと調べていないですが...
JUnit の Rule も そうですが、アノテーションってこんなに使えるものなんですね。
工夫次第でいろいろと役に立つモジュールができそうですね。
これはテストコードだけでなくプロダクトコードにも ぜひ 活用してみたいですね。

任意のフィーチャーメソッドだけを実行する

Spock でも JUnit4 のCategory と同じように 任意のテスト (フィーチャー) だけを実行することや逆にスキップすることができます。

方法は簡単です。
あらかじめ、Specification (テストクラス) もしくは フィーチャー (テストメソッド) に 好きなだけアノテーションをつけましょう。
あとは 設定ファイルに 実行したい (もしくはスキップしたい) アノテーションを 指定するだけです。

では、まずは アノテーションを作成しましょう。
今回は Java で作成しましたが、もちろん Groovy で作成しても OK です。

package com.bluepapa32;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface Fast {}
package com.bluepapa32;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface Slow {}
package com.bluepapa32;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface Server {}

次に 作成したアノテーションを Specification (テストクラス) もしくは フィーチャー (テストメソッド) に付けましょう。

@Server
class HelloSpec extends Specification {

     @Fast
     def "a fast method"() {
          expect: true
     }

     @Slow
     def "a slow method"() {
          expect: true
     }

     def "a neither fast nor slow method"() {
          expect: true
     }
}

後は 実行したいアノテーションとスキップしたいアノテーションを 次のように設定ファイルに設定するだけです。

import com.bluepapa32.*

runner {
    include Server        // 実行したいもの
    exclude Fast, Slow    // スキップしたいもの
}
上記は @Server が付いた フィーチャーのうち @Fast と @Slow が付いていないものだけを実行するように設定しています。
今回の場合だと "a neither fast nor slow method" だけが実行されることになります。

上記の設定は

  • システムプロパティ spock.configuration に設定したファイル (例: -Dspock.configuration=MySpockConfig.groovy)
  • クラスパス上の SpockConfig.groovy
  • ${user.home}/.spock/SpockConfig.groovy
のいずれかで設定できます。

もし、Eclipse を利用しているのであれば 以下のように設定ファイルを作成しましょう。
まず、Specification クラス用のソースフォルダとは別のソースフォルダ (例えば src/test/resources) を作成します。
次に、その直下に SpockConfig.groovy を上記の内容で作成します。
最後に Groovy の設定の 『Compiler』 の 『Enable script foler support』 にチェックをいれます。
これは src/test/resources 配下の groovy ファイルが class ファイルにコンパイルされないようにするためです。
と言うのも SpockConfig.groovy ファイルは設定ファイルですので groovy ファイルのままクラスパス上にコピーされる必要があるからです。



ちなみに 設定ファイルには アノテーションの他にも実行したい Specification を直接指定することもできます。
上記の HelloSpec の Slow 以外のフィーチャーメソッドだけを実行したい場合は以下のように設定します。

import com.bluepapa32.*

runner {
    include HelloSpec
    exclude Slow
}

Spock のメソッド名は識別子でなくてもよい

Java プログラマが 始めて Spock のコードを目にすると、何か違和感を感じると思います。
たぶん それは Java とは異なる 『メソッド』 と 『ブロック』 が原因だと思います。(もちろん Groovy シンタックスもですが...)

と言うことで、今回はメソッド名についてです。(ブロックについては そのうち...)
実は Spock のメソッドには Java のメソッドとは異なり 識別子以外の名称を使うことができるんです。
もう少し正確に言うと、シングルクォートで囲えば 識別子で使える文字でなくても使えるんです。

日本語はもちろんのこと "." や "( )" 半角空白、改行文字と言った通常 Java のメソッドでは使えない文字も使えます。
しかも 数字で始まるメソッド名だってちゃんと使えるんです。
ちなみに 『JavaSE 7でメソッド名に使えなくなった文字』 だって使えます。

一応、厳密に書いておくと...

ということで、Spock のメソッド名には そのメソッドの仕様を自分達が分かる言葉で簡潔に説明した文言 をそのまま使うのが良いです。
あと折角 最初の文字に数字が使えるので 仕様書のように分かりやすく項番を振っておくのもおススメです。
例えばこんな感じ...

def '1.1. 要素の中で一番大きな値を返す'() {
...
}

def '1.2. 要素がない場合は null を返す'() {
...
}

def '2.1. 要素の中で一番小さな値を返す'() {
...
}

def '2.2.要素がない場合は null を返す'() {
...
}

これをEclipse のアウトラインで見てみるとこんな感じです。 これはまさに仕様書...
いつかホントにドキュメントがなくなるときが来るかもしれませんね。


Eclipse の JUnit ビューを等幅フォントでいい感じに表示する

Spockでは (Groovy でも...) Power Assert と呼ばれる とっても便利な機能で エラー情報を詳細に出力してくれるのですが、 悲しいことに EclipseJUnit ビューはプロポーショナルフォントで表示されるので


のように非常に残念な結果になってしまいます。そんな時は


のように Groovyの設定で "Use monospace font for JUnit" にチェックを入れましょう。これで


のように等幅フォントでいい感じに表示されるようになります。
でも なんで普通にフォント設定で変更できないのだろうか?
とっても重要な設定なのに これはちょっと分かりにくいですよね...

教えていただいた id:nobusue さんに感謝!!

Eclipse で複数の Specification を一括実行する

Spock を使い続けていくと、当然ですが Specification ファイルはどんどん増えていきます。
実は Spock には Junit のテストスイートのような機能はありません。
つまり、Spock 自身には 複数の Specification を一括で実行する機能はないのです。

でもそんな時に役に立つのが Eclipse に用意されている 複数のテストクラスを一括で実行する機能です。
これは もともと JUnit の為に用意された機能ですが、もちろん Spock でも利用できます。

やり方は簡単です。
通常 Specification を実行する場合 実行したい Specification ファイルで右クリックして [Run As] --> [JUnit Test] を選択しますよね。
それと同じことを パッケージやソースフォルダでやれば、そのパッケージもしくはソースフォルダ配下の すべての Specification を実行することができるのです。


例えば、com.bluepapa32 パッケージで実行すると com.bluepapa32 パッケージ配下の Specification (上の場合 HelloSpec と HelloSpec2) がすべて実行されます。
とっても便利ですね。すべての Specification を実行するのに 一つずつ Specification を選択して実行してたら日が暮れてしまいますよね。 Junit のテストクラスも同じように実行できるので ぜひ試してみてください。

もちろん Gradle のようなビルドスクリプトを使えば、何も考えなくても すべての Specification ファイルが 一括で実行されるので、こんなこと気にする必要もないんですけどね...

Java プロジェクトに Spock を導入するための3ステップ

Java プロジェクトでユニットテストにお困りなら Spock を導入することをオススメします。
もし、Eclipse を使っているのであれば、たった3ステップで 既存の Java プロジェクトに導入できます。

「上の承認がないと導入できないし…」 とか 「ビルドスクリプト直さないとダメだし…」 とか いろいろと考えるよりもまずは導入してみましょう。その効果をみてから考えても遅くはないです。
では、早速 Java プロジェクトに Spock を導入してみましょう。

ステップ1. Groovy-Eclipse プラグインをインストールしよう

まず、最初に Groovy-Eclipse プラグインをインストールしましょう。
Groovy-Eclipse プラグインEclipse Marketplace から簡単にインストールできます。
ヘルプの Eclipse Marketplace を開いて "Groovy-Eclipse" で検索すれば直ぐにみつかります。
後は [Install] ボタンをクリックするだけで OK。便利な世の中になりましたね。


ステップ2. Groovy プロジェクトに変更しよう

既存の Java プロジェクトに Groovy Nature を追加します。
Java プロジェクトで右クリックして [Configure] --> [Convert to Groovy Project] を選択するだけです。
これで Groovy を使うために必要なライブラリがプロジェクトのビルドパスに追加され Groovy 使い放題です。


ステップ3. Spock のJARファイルをビルドパスに追加しよう

Spock のJARファイルを以下のURLからダウンロードしてビルドパスに追加します。

http://m2repo.spockframework.org/releases/org/spockframework/spock-core/0.5-groovy-1.8/spock-core-0.5-groovy-1.8.jar
もし JUnit4 がビルドパスに入っていないなら、ここで ついでに JUnit4 も追加しておきましょう。

これで EclipseJava プロジェクトで Spock を使うための準備は終わりです。
後は 好きなだけ Spec ファイルを作りましょう。

ここまで書いておいてなんですが...
ホントは こちら で紹介した ように Gradle で Spock するのが一番簡単でオススメなんですけどね。
でも Eclipse の方が取っ付きやすいですから...

と言うことで...
折角なので Spec ファイルを1つ作って実行してみましょう。

まずは メニューから [File] --> [New] --> [Groovy Class] と選択して、 以下のように入力すれば Spec ファイルを作成できます。
Superclass に spock.lang.Specification を設定する以外は特に普通のクラスを作成するのと 何も変わりません。


あとは

package com.bluepapa32

import spock.lang.Specification;

class HelloSpec extends Specification {
    def "length of Spock's and his friends' names"() {
        expect:
        name.size() == length

        where:
        name     | length
        "Spock"  | 5
        "Kirk"   | 4
        "Scotty" | 6
    }
}
のように 新しくフィーチャーメソッドを追加して JUnit と全く同じ要領で [Run As] --> [JUnit Test] で実行できます。
ちなみにSpockではテストメソッドのことをフィーチャーメソッドと呼びます。
実行結果も 以下のように JUnit と全く同じです。


エラーの場合も JUnit と同じように出力されます。
スタックトレースには Spock の特徴の一つでもある詳細なエラー情報 (Power Assert) が出力されます。

ただ、Eclipse だとプロポーショナルフォントで出力されるのでレイアウトが崩れてしまうのが非常に残念です。
スタックトレースのフォントの変更方法を知っている方はぜひ教えてください。


等幅フォントの設定方法を id:nobusue さんに教えていただきました。ありがとうございます。
設定方法については『Eclipse の JUnit ビューを等幅フォントでいい感じに表示する』を参照してください。

それでも Spock を使い続ける理由

2011年も残すところ後1ヶ月となりました。
12月と言えば アドベントカレンダーですが、技術系アドベントカレンダーには参加できなかったので勝手にやっちゃいます。
3日坊主だけにはなりたくないですが やれるところまでがんばってみるかな…

と言うことで 第1日目は 誰にも理解されず 約半年間 Javaユニットテストで Spock を使い続けてきた理由を挙げてみます。

まず Spock を知らない人のために...
Spock は Groovy ベースの BDD フレームワークで こんな感じで書きます。
ちなみに プロジェクトページは http://code.google.com/p/spock/ です。

class HelloSpock extends spock.lang.Specification {
    def "length of Spock's and his friends' names"() {
        expect:
        name.size() == length

        where:
        name     | length
        "Spock"  | 5
        "Kirk"   | 4
        "Scotty" | 6
    }
}  

BDD と聞くとなんか敷居が高いですが Spock はぜんぜんそんなことはありません。
BDD にこだわる必要なんかないんです。好きなように使っていいんです。Spock は...
もちろん TDD にだって使えます。難しいこと考えずに JUnit 使うくらいなら Spock 使いましょう。

ということで Spock を使い続けてきた理由です。

その1. 手軽に始められる

Spock は Groovy と JUnit をベースに作られています。
イマドキの IDE や ビルドツールであれば 大抵 Groovy も JUnit もサポートしているので Spock だって直ぐに使えるし、 Groovy は ほとんど Java と同じシンタックスなので、一般的な Java プログラマであれば 苦労することなく始められるはずです。
IDE のサポートさえあれば、とりあえず自分一人だって始められますよ。

その2. とにかく見た目が美しい

Spock のコードは とにかく少なくて見やすいです。一目見ただけで 直ぐに理解することができます。
もともと BDD のために開発されたフレームワークですので、当然コードを見ただけで簡単に仕様を把握できるように作られているのですが...
見やすさという点では 特に where ブロックはすばらしいです。
こんな感じで データを列挙するだけで たくさんの入出力パターンのテストが書けちゃうんです。

    where:
    name     | length
    "Spock"  | 5
    "Kirk"   | 4
    "Scotty" | 6
一度見ちゃうと JUnit には戻れなくなりますよ。
あと Mock も とっても分かりやすく書けるのでお気に入りです。

その3. エラー情報が半端ない

こんな感じです。ここまで必要なの?と思わずつぶやいてしまうくらい詳細に出力してくれます。

    Condition not satisfied:

    max(a, b) == c
    |   |  |  |  |
    3   1  3  |  2
              false

Spock の良さが少しでも伝わったでしょうか? 勝手にアドベントカレンダーはまだまだ続きます。
次回も Spock ネタかな。暫く引っ張りますよ。次はもう少し役に立つ情報を...