受け入れテストを日本語で書ける Jest 拡張 "Jest-gauge" を公開しました
先日 Daniel North の記事を訳していて、この記事がドラフトのままになっているのを思い出したので、加筆して公開することにしました。
概要
Gauge のように受け入れテストを日本語で書いて、 Jest を採用しているプロジェクトで受け入れテスト駆動開発 (ATDD) を実現できる Jest 拡張 "jest-gauge" を公開しました。
受け入れテスト駆動開発 (ATDD) とは
受け入れテスト駆動開発 (ATDD) とは、テスト駆動開発 (TDD) の延長線上にあるソフトウェア開発技法のひとつで、TDDが比較的にミクロにクラスやモジュールの動作への期待を書くことに注目するのに対して、ATDDはよりマクロな視点で、システムやサブシステム全体の受け入れ基準を記述することに注目しています。
かなり大雑把にいえば、TDDは単体テストに近いレイヤで、ATDDはE2Eテストに近いレイヤでのフィードバックサイクルを活用する方法論だといえます(ちなみに "Growing Object-Oriented Software, Guided by Tests" ではかなり抽象的に、TDDに内包する形で解説しています)。
ATDDと同じくTDDから発展して考案された手法のひとつに、振る舞い駆動開発 (BDD) があります。BDDは、TDDのフィードバックサイクルは維持したまま、「テスト」ではなくクラスやモジュールの「振る舞い」を定義することにフォーカスしています。TDDとの重要な違いは、ステークホルダーの参加です。TDDは基本的に、プログラマが自分の仕事をうまくやるために考案され、発展してきた手法ですが、BDDではプロダクトオーナー・開発者・テスターが参加する「ディスカバリー・ワークショップ」を通して、顧客に届けるべき価値を定義し、ユーザーストーリーに落とし込むことを重要視しています。
ユーザーストーリーは自然言語で書かれるので、動作するソフトウェアを巻き込んだフィードバックサイクルを動かすことができません。しかし、自動実行するためにテストコードをプログラムとして直接書いてしまうと、BDDの実践にはプログラムを読み書きできないステークホルダーも参加するので困ります。
そこで、 BDD のための有力なツールである Cucumber では、ディスカバリー・ワークショップで探索した知見を自然言語に近いかたちで結晶化する方法として、 Gherkin という DSL を提供しています。 Gherkin では、巷でよく使われるユーザーストーリーのテンプレートと似たような感じで、「顧客として、銀行の列に並ばずに済むように、ATMで現金を引き出したい」などと書くことができます。これなら、プログラムを読み書きしないステークホルダーも理解することができそうです。
Daniel North も Eric Evans のユビキタス言語を参考にしたと書いているとおり、これはドメイン定義であり、事業オーナーのプロダクトに対する「受け入れ基準」「品質基準」に他なりません。この基準を、Bob Martinが言うように「ソフトウェアの実行可能な仕様定義」に落とし込み、ソフトウェア開発を駆動していくことができないだろうか、というのが、受け入れテスト駆動開発の動機です。
なぜ Gauge か
こう見ると、BDDとATDDには大きな違いがないように見えます。大きな違いがないのであれば、BDDのツールである Cucumber は、細かいミスマッチに目を瞑れば、ATDDにも転用できるのではないでしょうか。
私が特に課題を感じたのは、 Gherkin が結局は自然言語ではなく、形式言語だと言う点です。書き上がった Ghekin の振る舞い記述は自然言語のように見えるのですが、書こうとすると、エンジニアでないステークホルダーにはなかなか難しいようでした(プログラムを書く人にはあるあるだと思うのですが、個人的にはエンジニアでない人でも RSpec くらいの記法であればなんとなく書けるだろうと思ってしまう節があります。実際には全然そんなことはないのですが、海外でも割とみられる認知バイアスのようです)。
Cucumber/Gherkin ではステップ定義(振る舞い記述に対して、どのような動作をして動作を検証すべきかを定義する、テストコードの一部)をセンテンスに対応づけて使いまわせるのが便利なのですが、センテンス以外の文法構造は形式的に制約されていますし、日本語の場合、活用の関係で語幹が変わってしまいうまくマッチしないなど、なかなか使いづらい場面が多かったのを覚えています(7-8年前の話なので、今は改善されているのかもしれませんが)。
その点、 Gauge では非形式的な自然言語で仕様を書くことができます。仕様定義ファイルそのものは Markdown のサブセットとして緩く形式的に定義されているのですが、その中に記述するセンテンスは、単なる自然言語です。
# トップページの仕様
本文はすべてコメントの扱い。ユーザシナリオの背景や動機を自由に書くことができます。
## シナリオ: ユーザはサイトを開き、トップページを表示することができる。
* "https://duckduckgo.com/" を開く。
* きゅうりのような顔をしたかわいい鳥の画像が表示される。
その代わり、ステップ定義としてはセンテンス全体での完全一致が基本となります。テンプレート文字列を挿入して柔軟さを持たせることもできます。やりすぎると形式言語っぽさが強まってしまうのでトレードオフではあるのですが、その度合いを自分たちでコントロールできる点で優れていると思います。
非形式的な自然言語で仕様や受け入れ基準を記述できることから、個人的には Gauge にとても興味を持っています。
なぜ Jest-gaugeか
Gauge はかなり opinionated な構成になっていて、既存のプロダクトに後から導入するのがやや高コストに感じました。特に、ようやく単体テスト・E2Eテストを Jest で作成する文化が根付きつつあるチームで、「今日からE2Eテストは受け入れテストと呼び名を変えて、フレームワークには Gauge を使います!」というあまり生産性のないインパクトを与えるのは、気が進まないことでした。
そうはいっても、 Gauge の多くの機能が全体として ATDD の導入を支援してくれるのだと思うので、本格的に ATDD を実践するのであれば、どこかで Gauge を導入するべきなのだと思います。しかし、私は今回検証したいテーマを、「 ATDD はアリかナシか?」よりも少し狭く、「エンジニア組織と、非エンジニアのステークホルダーが、Gaugeのような日本語による受け入れテストを通して対話することが可能か?」と定義していました。
そこで、既にJestで単体テストとE2Eテストを書き始めているチームが、Gaugeのような日本語による受け入れテストを手軽に導入できるツールを作ろうと思い立ち、開発のきっかけとなったチーム以外でも活用したいので、OSSとして公開することにしました。
インストール方法・使い方は、リポジトリのREADMEを参照してください。
Jest 拡張として実装しているので、 Jest の設定を追加するだけで使い始めることができます。前述の仕様であれば、テストを実行すると次のような Jest のレポートが出力されます:
$ npx jest --config=jest.config.gauge.js specs/
PASS examples/welcome.spec
トップページの仕様
シナリオ: ユーザはサイトを開き、トップページを表示することができる。
✓ "https://duckduckgo.com/" を開く。
✓ きゅうりのような顔をしたかわいい鳥の画像が表示される。
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.913 s
Gauge の機能のうち主要なところはサポートしていますが、まだサポートしていない部分もたくさんあります。どの程度の部分をサポートしているかは、READMEのTODOの節で整理しています。
開発のきっかけ
開発のきっかけになったのは、私が関与しているプログラミングスクール Code Village の学習管理システムの開発プロジェクトでした。プログラミング経験はあまりない運営スタッフがステークホルダーとして関わるプロジェクトで、彼らは「こういう機能がほしい」という声をたくさん挙げてくれました。教育現場での生の声が反映されたとても濃い知見の集まりではあったのですが、雑然とした Excel データでもあったので、これをソフトウェアのかたちに落とし込み、価値として送り出すまでをどのように管理すれば良いか少し考えることになりました。
そこで最近ATDDに興味を持っていた私は、「プログラミングスクールなので、普通のビジネスよりソフトウェア開発技術でチャレンジしてもいいのではないか。何か知見が得られれば、スクールの教育レベルにもフィードバックできると思うし」と、普通はあまり通らないワガママを言わせてもらいました。開発メンバーですら若干面食らっていたので、受け入れてくれた運営スタッフや他の役員陣には感謝しかありません。
ちなみにワガママはそれだけでなく、スクールでの講義やサポートに使うビデオチャットを WebRTC で自前実装するというチャレンジにも取り組むことができました。下図は学習管理システムに組み込まれたビデオチャットで、ZoomやAgoraなど有名どころのSaaSやAPIを使用せずに実装しています。接続性が安定するまでには多くの課題を乗り越える必要がありましたが、おかげで開発チームの連帯と知見は大幅に深まりました。
そんなこんなで、2021年のATDD事情を深堀りし、経験のある Cucumber/Gherkin の現状にキャッチアップした上で、Gauge の導入手順を検討した結果、 Jest-gauge を書くことを決めました。それ以来、スクールのCIでは日本語で記述された受け入れテスト(この時点での効用はレグレッションテストになりますが)が毎日実行されています。
というわけで一応プロダクションでの導入事例はあります(笑)。
が、前述の通りの経緯と、そこまで大きくない規模のおかげで許容できるリスクに収まっているところです。まだまだかなりラフな実装なので、お使いになる場合はご注意ください。
今後
GOOS を始め、 ATDD に関する文献を漁っていると、BDDやDDDが提唱していた「ソフトウェア技術者とそれ以外のステークホルダーが、振る舞い記述やユビキタス言語を通じて、エビデンスベースでコミュニケーションできる世界」は、少し早すぎた理想だったのではないか、と感じます。
デジタル技術の普及が進み、非エンジニアのステークホルダーも十分なデジタルリテラシを持つようになれば、 Gauge や Cucumber のようなもので書かれた半形式的言語を通じてプロダクトの共通認識を深めることができる世界も遠からず訪れるのではないかと思います。
プログラミングスクールの運営会社は、その性質上、開発スタッフ以外でもデジタルスキルの高い人材が多い、少なくともソフトウェアに関するスキルを高めようという意思の高い人材が多いように感じます。結果として、非エンジニアのステークホルダーを巻き込んだ ATDD の実践がやりやすいようです。そこで Jest-gauge を使って ATDD の実践を重ね、いずれはよりソフトウェアと離れた領域でも活用できる知見とツールに育てていきたいなと思っています。
ただまだ試しているだけなのでどうなるかはわかりません。ライブラリは、オープンソースで誰でも使えようにしてあります。もしお使いになって、何か良くも悪くも知見が得られたら、ぜひご共有いただけると幸いです。コントリビュートも歓迎です。
Discussion