Gherkin記法はじめました
はじめに
End-To-Endでの、システム統合テストや受け入れテストに自動テストを導入するにあたって、Gherkinという、テスト記述の記法を知った。QAエンジニアの立場で、自動テストを導入する方法として、よさそうに感じたので、そのときに調べたことをこの記事にまとめる。人に読んでもらうものというよりも、メモに近い。
そもそも Gherkin は、Behavior-driven development (以下、BDD)という開発手法で使用されるテスティングフレームワークで用いられる記法である。また、BDDは、Test-driven development (以下、TDD)の派生である。まずは、そのTDD、BDDについて、簡単にまとめる。
Test Driven Development
前提として、TDDとは開発手法もしくは設計手法の1つであり、テストの手法ではない。あくまでも「手段」としてテスト(テストコード)を用いた開発方法である。
テストファーストによる追加・変更と、リファクタリングによる設計改善の2つの活動を超短期で繰り返して開発を進めていく技法である。RED/GREEN/REFACTORのサイクルを回すとも表現される。これにより「素早くフィードバックを得る」という目的を達成する。具体的には、以下のように進める。
- 失敗するテストコードを書く。このテストは、コードが求められる機能を表す。また、テストを実行可能にするために、テスト対象となるコードを実装する。ここでは、テストが実行可能になれば、どんなコードを実装してもよい。
- テストが成功する様にテスト対象コードを変更する。
- 別のテストケースの失敗するテストコードを追加する。
- テストが成功する様にテスト対象コードを変更する。
- テストが成功する状態を保ったままテスト対象コードをリファクタリングする。ここでのリファクタリングは、テストを動作させるためだけに作成された重複を全て取り除く作業になる。(REFACTOR)
TDDのアプローチ手法は、以下の2とおりある。それぞれProc/Consがある。テスト駆動開発/振る舞い駆動開発を始めるための基礎知識が参考になる。ここでは、流派の呼び方と、それぞれのバイブル的書籍を記載する。
- inside-out TDD: デトロイト派、古典派
- バイブル: テスト駆動開発(Test Driven Development By Exampleの日本語訳版)
- outside-in TDD: ロンドン派、モック派
- バイブル: 実践テスト駆動開発
以下は、TDDにおける原則や指標について記述する。
Kent BeckのいうTDDの原則 from『テスト駆動開発』
自動テストが失敗した場合だけ、新しいコードを書く。重複を取り除く。2つの規則はプログラミングのタスクにおける順番を意味する。
レッド: 動作しないテストを少しだけ作成する。おそらく最初はコンパイルできない
グリーン: テストをすぐに動作させる。そのためには、どのようなコードでもよい
リファクタリング: テストを動作させるためだけに作成された重複を全て取り除く
Robert.C.MartinのいうTDDの原則 from 『Clean Code』
3つの原則を守りながら実装を進める。
- 失敗するテストができるまでプロダクトを書いてはいけない
- 失敗するテストがある場合にはそれ以上テストを追加してはいけない
- テストを成功させるプロダクトがある場合にはそれ以上プロダクトを追加してはいけない
TDD では、実装対象のユーザーの立場でテストする。ここでいうユーザーは、これから実装しようとしているものを使う人を指す。あるモジュールやクラスを実装しようとしているときは、そのモジュールやクラスを使う人が、ユーザーとなる。もっと上位のレイヤーであれば、エンドユーザーから見える機能になれば、エンドユーザーやプロダクトオーナーがユーザーとなる。ユーザーは実装対象によって異なる。
また、実装するテストコードは説明的で読みやすい文章であるべき。例えば、対象のメソッドに対する説明ではなく、「対象がどのような変化を生むのか」を書くべきである。
Behavior Driven Development
BDDは、日本語では、「ふるまい駆動開発」などと訳される。Dan Northにより提唱された技法。詳しくは「BDDの導入」を参照すると良い。TDDを進めていく中で、「何をテストすべきか」「テストとは何か」といった問いに対しての説明として"Test"ではなく"Behavior"という言葉を使って説明する方が開発者にとって理解しやすかった、というDan Northの経験から生まれた。いわゆる「TDDのテストはテストではなく、そのコードが求められる機能を表す」という考えを理解しやすい様にする役割を持つ。BDDの解釈についての記事は参考になる。
BDDは、アジャイルソフトウェア開発での技法のひとつで、エンジニアとQAエンジニアと非エンジニア(プロダクトマネージャ/オーナーやステークホルダー)間のコラボレーションを手助けする開発技法である。その要因は、テストがソフトウェアに期待される振る舞い(機能的な外部仕様)に特化した記述に基づいて行われることにある。これにより、ユーザーの要求やアーキテクチャの設計仕様といった、より上位のインプットとTDDのテストにつながりを持たせている。
BDDフレームワーク
Behatの制作者であるKonstantin Kudryashovは、以下の2つの相補的なBDDフレームワークを提唱している。
- SpecBDD
- StoryBDD
以下にそれぞれのフレームワークの役割を示す。
SpecBDD
SpecBDDは、内部構造に寄った実装レベルの仕様を表現し、低レベルなテスト、いわゆる単体テストで用いられる。
代表的なフレームワークを以下に示す。
以下に上記フレームワークでの一般的な記述例を示す。
describe("Authentication", () => {
describe("in login page", () => {
context("with valid credentials", () => {
it("should success to login", () => {
// Arrange
const user = new User("email", "password");
// Act
const success = user.login();
// Assert
expect(success).toBe(true);
});
});
});
});
この記述の特長を以下に示す。
-
describe
のネストにより、テストのコンテキストを表現できる
ネストされたdescribe
の第一引数を一つの文として読み下すことで、テストのコンテキストを理解できる。上記の例では、Authentication in login page
となる。 -
context
によりテスト条件を記述する
describe
のエイリアス。テストの条件であることを明示的にするために用いる。これによりテストのコンテキストを理解を向上させる。describe
のネストと組み合わせて読み下すと、Authentication in login page with valid credentials
となる。 -
it
によるテスト記述
上記の例ではit should success to login
と読み下すことができ、ソフトウェアの振る舞いをそのまま記述できる。
StoryBDD
StoryBDDは、ScenarioBDDとも呼ばれ、ソフトウェアの機能性についてのふるまいをユーザー視点からシナリオとして表現する。このシナリオ自体はテストではなく、ビジネス面において興味深いものを除いて、すべてのアプリケーションの機能をターゲットにする目的もない。しかし、シナリオを用いて開発物の受け入れ段階のテストを自動化することができる。その際用いる代表的なフレームワークとして、Cucumberがある。Cucumberでは、シナリオ記述にGerkin記法を用いる。
Gherkin 記法
ここからが本題のGherkin記法。
Gherkin記法とはシナリオ記述フォーマットの1つで、「こういう状態のとき、こういう動作を行えば、こうなることが期待される」という形式でシナリオを記述する。
以下の理由から非エンジニアでも、どんなことがテストされているかがわかりやすいのが特長。
- 自然言語を使用して記述する
- 仕様部分を独立して記述する
- とにかく構文が端的で平易な書き方になる
以下に簡単な例を示す。
Feature: きゅうりを食べる
# description
人がきゅうりを食べるときの振る舞い
Scenario: 数十本のきゅうりを食べるとお腹が満たさせる
Given: 太郎は空腹である
When: 太郎はきゅうりを50本食べる
Then: 太郎は満腹になる
Gherkin記法では、キーワードと呼ばれる修飾子を用いて振る舞いを記述する。それぞれ以下の様な役割を持つ。詳細はcucumberのリファレンスを参照のこと。日本語訳している記事もある。
-
Feature
: ソフトウェアの機能を記述。関連するScenario
をまとめる役割も持つ。 -
Scenario
: 機能に対する具体的なルールを説明する。以降に続くSteps
の内容と一致する様に記述すること。 -
Steps
-
Given
:振る舞いまたはアクションを受け取るシステムの状態(前提条件)を記述する。 -
When
: 最終結果を引き起こす振る舞いまたは実行内容を記述する。 -
Then
: 所定の状態で所定の振る舞いによって引き起こされる結果(期待結果)を記述する。 -
And
/But
: 各ステップを連続して記述する場合に用いる
-
シナリオを書くときの心構え
Steps
のGiven
, When
, Then
のキーワードによる記述は、ユニットテストの、Arrange-Act-Assert (AAA)に構文が類似しているように感じる。AAAは、テストコードを「準備」「実行」「検証」に分けて、それぞれができるだけひとまとまりになって記述することで、テストコードが読みやすくなるという考え。Steps
に記述する内容が、なにを示しているものなのか、それに相応しい修飾子を用いることが大切。
Steps
にAnd
やBut
のキーワードを多く用いて、長いシナリオを記述することができる。しかし、つらつらと長いシナリオを描くと、「結局、何をテストしているの?」など、シナリオの可読性が落ちる。結果的に、シナリオの保守性が下がる。保守性の高い状態でテストシナリオを記述する際に役立つ原則に「BRIEFの原則」がある。この原則について書かれた記事「Keep your scenarios BRIEF」が参考になる。日本語訳版もある。
- B: Business language
ビジネスチームのメンバーが明確に理解できるように、ビジネスドメインで用いられる言語を用いてシナリオを記述する。
アンチパターン: さまざまなコンテキストでさまざまな意味を持つ用語を使用する(たとえば、アドレス、ユーザー、日付、アカウントなど)。 - R: Real data
実際のデータを使用して、シナリオを作成する。 - I: Intention revealing
意図を明らかにする。
アンチパターン: シナリオ内にUIの用語を使用する(たとえば、ボタンをクリックする、リンクをたどるなど)。 - E: Essential
シナリオの目的は、ルールがどのように振る舞うかを説明すること。この目的に直接関与しない部分は、削り落とし、本質的な部分のみで記述する。 - F: Focused
1つのルールの説明に焦点を絞るべきである。 - Brief
5行以下に制限することを推奨。これにより、読みやすくなり、意図を捉えるのもはるかに簡単になる。
ちなみに、Gherkin記法を用いるテスティングフレームワークを導入したからといって、そのチームがBDDの手法で開発していることになるわけではない。いうなれば、「BDDをサポートするテスティングフレームワーク」である。
Discussion