小ネタ) SpockのData Driven Testingでテスト観点をUnrollのメソッド名に記述するとよいかもしれないと思った話

Spockのデータ駆動テスト(Data Driven Testing)では、メソッド名としてデータ変数を含んだ文字列を使うことで、テスト結果を見た時にどこで失敗したか、わかりやすくすることができます。

データ駆動テスト — Spock 1.0-SNAPSHOT

さて、この時に利用するデータ変数は、テストで利用するパラメータと期待値を使うことが基本だと思います(実際ほとんどのケースではそれで十分だと思いますが)。

しかし、イテレーション(テストのパターン数)が増えてきたり、複雑なロジックのテストの場合、パラメータと期待値だけでは、そのパターンのテスト理由・意図が一見してわからないこともあります。その時、テスト観点も含めると便利だと思ったので、紹介します。

デフォルト

そもそもデータ変数をメソッド名として使わない場合、例えば、こんな感じのテストがあった時、

    @Unroll
    def "maximum of two numbers"() {
        expect:
        max(a, b) == ans

        where:
        a  | b   || ans
        3  | 4   || 4
        -3 | -4  || -3
        10 | 10  || 10
        10 | -20 || 10
        0  | 5   || 5
        -5 | 0   || 0
    }

個々のメソッド名はイテレーションのインデックスだけで区別されます。

f:id:jappy:20170114073900p:plain

パラメータと期待値

メソッド名を次のように変えると、

    def "maximum of two numbers (#a, #b) -> #ans"() {

どのケースで失敗したかが一目瞭然になります。

f:id:jappy:20170114074230p:plain

(このキャプチャではすべてpassしていますが)

テスト観点を加える

今度は、以下のようにしました。

    @Unroll
    def "maximum of two numbers (#a, #b) -> #ans (#description)"() {
        expect:
        max(a, b) == ans

        where:
        description << [
                'positive & positive',
                'negative & negative',
                'same',
                'positive & negative',
                'zero & positive',
                'zero & negative'
        ]

        a  | b   || ans
        3  | 4   || 4
        -3 | -4  || -3
        10 | 10  || 10
        10 | -20 || 10
        0  | 5   || 5
        -5 | 0   || 0
    }

ポイントは2つで、

  • データ変数として、テスト内で直接使うわけではないが、テスト観点・意図を表す description を追加する
  • テスト観点は長くなりがちなので、データテーブルの可読性を下げないように、データテーブルの列ではなく << オペレータで列挙する

実行結果は想像がつくと思いますが、以下のようになります。

f:id:jappy:20170114075047p:plain

おわりに

上の例だと単純過ぎてあまりメリットが見えにくいですが、実際に業務でテストコードをレビューしていてこんなことがありました。

  • テスト対象のロジックが複雑(パラメータの組み合わせ)なため、データテーブル中にコメントを書いて、テスト目的を分かるようにしていた。
    (コメントに書くくらいなら、テストメソッド名になっていた方が、CIでのレポート結果などでもすぐに分かるので、有用だと思います)
  • パラメータや期待値が複数の項目から成るリストで、データ変数としてそのまま展開するとものすごい長いメソッド名になってしまい、テスト結果の一覧性を悪くしていた。

なので、その辺りをちょっとだけ改善するために、テストの意図を表す文字列をメソッド名に含めるとよいのでは?と思ったのでした。