A-TDDのツールとしてCucumberを候補に挙げつつ、同時にCypress等の最近のE2Eテストツールを調査している過程で発見した新興A-TDDツールを調査した。

A-TDDとは

A-TDDとはAcceptance Test Driven Developmentの略で、受け入れテスト駆動開発のこと。 開発の冒頭でプロダクトオーナーやステークホルダーと受け入れテストの内容を握り、それに基づいてプロダクトを開発する手法のこと。 受け入れテストの内容を実行可能な自動テストとすることで、常にプロダクトが受け入れテストの求める顧客価値を実現しているか確認できる。

A-TDDという言葉はプロダクトオーナーやステークホルダーと、受け入れテストの内容でコミュニケーションを取ることを念頭に置いた命名であり、エンジニアリングの視点のみで語られる際にはBDD(Behavior Driven Development)と呼ばれる。

JUnitなどを用いたUnitTestと組み合わせることで、常にリリース可能なプロダクト開発を実現することができる(はず)。

Cucumberの紹介

A-TDDの先駆けとも言えるCucumberについて紹介する。 CucumberはA-TDDを実現するツールであり、以下のようにGherkinという記法で受け入れテストを記述できる。

# Comment
@tag
Feature: Eating too many cucumbers may not be good for you

  Eating too much of anything may not be good for you.

  Scenario: Eating a few is no problem
    Given Alice is hungry 
    When she eats 3 cucumbers
    Then she will be full

https://docs.cucumber.io/ より引用

Featureは1つの機能を表し、その機能を表現するシナリオをドキュメントとして記述していく。このGherkin記述と共にStepと呼ばれるJavaやRubyでのE2Eの実装を準備し、Given/When/Thenなどの記述の1行ごとにこれらを紐付けることで受け入れテストに相当するE2Eテストを構成していく。 Featureは機能、Scenarioはシナリオ…といった翻訳で日本語でも記述できる。

Cucumberの限界(単なる記法の充実度の問題)

Cucumberの記述方法でプロダクトオーナーやステークホルダーと要求内容・要件確認が握れるならそれで問題は無い。 実際には上記の人間以外にも、セールスやサポートに関わる要員からの問い合わせなどのために、Cucumberによる記述以外のドキュメントを求められることが想定される。 しかし、人間が現行仕様をドキュメントに落とし込む作業は避けるべきだ。その仕様がどの時点でも正しいことを誰が担保するのか。誰も担保しはしない。

そのドキュメントが正しいことを自動的に確認できないドキュメントは早々に嘘になる。

Gaugeの紹介

Gauge(ゲージと読むっぽい)の紹介をする。Cucumberにおける記法の問題を、このGaugeによって全て解決できるとは思わないが、ことドキュメントとしての充実度はCucumberより高い。 Gaugeにおける受け入れテストの記述を見てほしい。

# Search specification
Tags: search, admin

The admin user must be able to search for available products on the search page

* User must be logged in as "admin"
* Open the product search page

## Successful search
Tags: successful

For an existing product name, the search result will contain the product name

* Search for product "Die Hard"
* "Die hard" should ahow up in the search results

## Unsuccessful search

On an unknown product name search the search results will be empty

* Search for product "unknown"
* The search results will be empty

どこかで見覚えないだろうか、実は単なるMarkdownである。 Specificationを h1 に相当する # の行で表現し、各シナリオを h2 に相当する ## で表現する。 タグや説明文なども存在するが、残りは * で始まるStepで、ここが各言語でのE2Eテスト実装との連携ポイントとなる。 Stepには以下の通りデータテーブルを付与することができ、複数の値をStepで受け取りE2Eでの処理を記述できる。

* Create the following projects
    |project name| username |
    |------------|----------|
    | Gauge java | <name>   |
    | Gauge ruby | <name>   |

参考: Writing Specifications — Gauge 1.0.0 documentation

Step実装

Step実装にはC#/Java/JavaScript/Python/Rubyが存在し、この中で任意の言語でStep実装できる。

public class Users {
    @Step("Create following <race> characters <table>")
    public void createCharacters(String type, Table table) {
        // Step implementation
    }
}

このStep定義で、 Create following <race> characters <table> のパターンにマッチするA-TDDの記述と連携が行われ実行される。

A-TDDテストの価値は

実行可能な仕様書が残ることの安心感

先述の通り、その仕様書が正しいことを担保できない「単なる仕様書」は、よほど強制力の高い完璧な業務プロセスが存在していない限り、早々に嘘まみれになってしまう。 つまり、仕様を調べようと頑張って仕様書を見つけ出したとしても、その次の作業は「その仕様書が正しいことの確認作業」になってしまう。 「実行可能な仕様書」であれば、それが正しいことの担保は、ただ実行すれば良いだけとなるし、CI周りが整っていれば、ビルドやリリースのたびに確認が済まされているはずだ。

これには例外が含まれており、仕様書と、それと連動するStepの実装が乖離している場合には、仕様書が嘘まみれになる可能性は依然として存在する。 しかし、エンジニアが全員プロフェッショナルであれば、そのようなStep実装は扱うのが不愉快で放置できないはずだ。

非エンジニアとのコミュニケーション円滑化

A-TDDの主たる目的は受け入れテスト駆動開発だ。ここで言う「受け入れテスト」とはプロダクトオーナーやステークホルダーが提示する要件の「受け入れ可能な条件」を記述したものとなる。 ここに記述された文面をもって上記の担当者と仕様を握ることができ、テストファーストな開発のプロセスの中で、常に「作っているものが要求を満たしているか?」を確認しながら実装を進めていくことができる。

例外はデザイン面で、これはCucumberでもGaugeでも担保できない。

E2Eテストのメンテナンスの困難を解消

既存プロダクトに対して、機能の保証のためのE2Eテストを実装・メンテナンスしていくことの困難さは、【自動化】ワーストプラクティス 〜まずはやってみる〜のイベントでも、次のようなポイントで複数の方々から述べられていた。

  • Webデザイナとの協業の困難さ(E2Eと無関係にデザイン要件でE2Eが落ちる)
  • E2Eそのものの不安定さ(WebサーバやSeleniumの内部の問題でたまにE2Eが落ちる)

上記の問題は「実装に合わせてE2Eテストを構成する」ことにより発生している部分が大半であり、「E2E(A-TDD)が通るように機能実装を行う」よう進めれば問題は発生しない。 (「たまにE2Eが落ちる」部分の一部に関しては例外も存在する…)

さいごに

Gaugeをまだ試してもいないのにCucumberで得た達成感と、同時に感じた課題感をもとにここまで書いてしまった…。 Gaugeの試用が行い語れるものが出来次第、この記事は追記を行う。