19
10

More than 3 years have passed since last update.

Karateを始めるので、Gherkin記法を理解する

Posted at

この記事は

Gherkin Referenceを抜粋して日本語訳したもの+個人的に追加したサンプル。
Karateをやってみようと思うので、まずはGherkinに慣れる必要あるかなと思った次第。
多分日本語のドキュメントもどっかにあると思うんだけど、備忘録的とか勉強的な意味合いなので自分で翻訳してみることにする。
また、Gherkin ReferenceはCucumber向けのドキュメントであるため、本記事を読む際はそこだけちょっと気を付ける必要がある。

知りたいことはいろいろあるが、現在はデモ用の.featureファイルを読めない程度の理解度であるから、これを理解できるようにすることを第一目標とする:

users.feature
Feature: sample karate test script
  for help, see: https://github.com/intuit/karate/wiki/IDE-Support

  Background:
    * url 'https://jsonplaceholder.typicode.com'

  Scenario: get all users and then get the first user by id
    Given path 'users'
    When method get
    Then status 200

    * def first = response[0]

    Given path 'users', first.id
    When method get
    Then status 200

  Scenario: create a user and then get it by id
    * def user =
      """
      {
        "name": "Test User",
        "username": "testuser",
        "email": "test@user.com",
        "address": {
          "street": "Has No Name",
          "suite": "Apt. 123",
          "city": "Electri",
          "zipcode": "54321-6789"
        }
      }
      """

    Given url 'https://jsonplaceholder.typicode.com/users'
    And request user
    When method post
    Then status 201

    * def id = response.id
    * print 'created id is: ', id

    Given path id
    # When method get
    # Then status 200
    # And match response contains user

Gherkin記法

Keywords

空行でないすべての行は、以下のGherkinキーワードから始める必要があります。ただし、FeatureScinarioに対してdescriptionsを記述する場合はその限りではありません。
プライマリキーワードの一覧:

  • Feature
  • Rule (as of Gherkin 6)
  • Example (or Scenario)
  • Given, When, Then, And, But for steps (or *)
  • Background
  • Scenario Outline (or Scenario Template)
  • Examples (or Scenarios)

セカンダリキーワードの一覧:

  • """ (Doc Strings)
  • | (Data Tables)
  • @ (Tags)
  • # (Comments)

Feature

Featureキーワードは、ソフトウェアの機能や関連するシナリオへの抽象度の高い説明を提供します。
Gherkinドキュメントにおける最初のキーワードはFeatureでなければならず、そのあとには:を付与しなければなりません(要はFeature:)。このあとに、機能を説明する短いテキストが記載されます(例:Feature: my first API test)。
更に説明が必要である場合は、改行してテキストを追加することができます。
追加したテキストはCucumber実行時に無視されますが、レポートには記載されます(例えば公式のHTMLフォーマッタ)。

sample.feature
Feature: sample karate test script
  for help, see: https://github.com/intuit/karate/wiki/IDE-Support
  As you know, this is a sample description.
  I do this for checking how the description will be expressed in HTML report.

↑を記述したときの.htmlレポート:
feature.jpg

Descriptionsについて

Featureに追加でテキストを記載できると説明しましたが、Example, Scenario, Background, Scenario Outline, Ruleに対しても同じことができます。
基本的には自由にテキストを記述できますが、キーワードを行頭に記述してはいけません(=Feature, Example, Scenarioといったワードが、その行の最初に記述されてはいけない)
Descriptionsは、Markdown形式で記述することができます。official HTML formatterを含むフォーマッタも、これをサポートしています。

Rule

(optional) Ruleキーワードはv6からGherkinの一部になりました。
Ruleキーワードの目的は、実装されるべきビジネスルールを表現することです。これは、featureに追加の情報を提供します。Ruleは、そのルールに所属する幾つかのシナリオに対してまとめて使用されます。ルールは、特定のルールを説明する1つ以上のシナリオから構成されます。

例:

sample_rule.feature
# -- FILE: features/gherkin.rule_example.feature
Feature: Highlander

  Rule: There can be only One

    Example: Only One -- More than one alive
      Given there are 3 ninjas
      And there are more than one ninja alive
      When 2 ninjas meet, they will fight
      Then one ninja dies (but not me)
      And there is one ninja less alive

    Example: Only One -- One alive
      Given there is only 1 ninja alive
      Then he (or she) will live forever ;-)

  Rule: There can be Two (in some cases)

    Example: Two -- Dead and Reborn as Phoenix
      ...

Example/Scenario

これはビジネスルールを説明する具体的な例です。これは、ステップのリストから構成されます。
Scenarioキーワードは、Exampleキーワードの同意語です。
あなたは好きなだけステップを記述することができますが、exampleごとに3-5ステップとすることを推奨します。ステップが増えすぎると、仕様やドキュメントとしての表現力を失う原因になるからです。
Exampleは仕様やドキュメントのほか、テストにもなります。全体として、あなたが作成するExampleはシステムの実行可能仕様となるでしょう。

Exampleは、以下のパターンに従います:

  • 初期コンテキストの説明 (Given steps)
  • イベントの説明 (When steps)
  • 期待される出力の説明 (Then steps)

Steps

それぞれのステップは、Given, When, Then, And, またはButから始まります。
Cucumberはシナリオ内のステップを1つずつ実行します。実行順序は、あなたが記述した順序です。Cucumberがステップを実行するとき、Cucumberは実行するステップの定義を探します。
ステップの定義を探す際、キーワードは考慮されません。これは、あなたがGiven, When, Then, And, またはButと同じテキストをを持つステップを別のステップとして保持することができないことを意味します。

Cucumberは、以下のステップを複製であると認識します:

step_sample1.feature
Given there is money in my account
Then there is money in my account

以下の場合は制約に引っかかりそうですが、Cucumberはあなたにより曖昧でない、よりクリアなdomain languageを提案するよう強制するでしょう:

step_sample2.feature
Given my account has a balance of £430
Then my account should have a balance of £430

Given

Givenステップはシステムの初期コンテキスト(シナリオのシーン)を説明するために使われます。典型的には、過去に発生した何かです。
Cucumber がGivenステップを実行する際には、オブジェクトを生成・設定したりデータをテスト用データベースに追加するなど、システムをwell-definedな状態に設定します。
Givenステップの目的は、ユーザー(または外部システム)がシステムと交信する前にシステムをknown stateにすることです。
Givenステップは複数記述することができます(可読性を上げるため、2番目以降はAndまたはButを使用してください)。

例:

  • Mickey and Minnie have started a game
  • I am logged in
  • Joe has a balance of £42

When

Whenステップはイベントやアクションを説明するために使われます。これはシステムと交信する個人や、他のシステムからトリガーされるイベントのことでもあります。
1つのシナリオには、1つのWhenステップのみ記述することを強く推奨します。無理にWhenステップを追加することは、通常シナリオをより小さい複数のシナリオに分割する必要があることを示唆します。

例:

  • Guess a word
  • Invite a friend
  • Withdraw money

Then

Thenステップは期待される出力や結果を説明します。
Thenステップの定義は、actual outcome(システムの実挙動)とexpected outcome(システムがするはずの挙動)の比較をするアサーションであるべきです。
outcomeは、観測できる出力であるべきです。それは、システムから出てくるもの(レポート、ユーザーインターフェース、メッセージ)で、システムに深く埋め込まれた振る舞いではありません(データベースのレコードのようなもの)。

例:

  • See that the guessed word was wrong
  • Receive an invitation
  • Card should be swallowed
  • While it might be tempting to implement Then steps to look in the database - resist that temptation!

あなたは、ユーザー(または外部システム)から観測できるoutcomeだけを検証するべきであり、通常はこれをデータベースにはしません。

And, But

あなたがもし、Given, When, Thenを連続して記述したいとき、次のように書くことができるでしょう:

sample_and_not1.feature
Example: Multiple Givens
  Given one thing
  Given another thing
  Given yet another thing
  When I open my eyes
  Then I should see something
  Then I shouldn't see something else

または、Given, When, ThenAnd, Butに置換して、Exampleをfluidly structuredな形にすることもできます:

sample_and_not2.feature
Example: Multiple Givens
  Given one thing
  And another thing
  And yet another thing
  When I open my eyes
  Then I should see something
  But I shouldn't see something else

*

Gherkinは、通常のステップキーワードの代わりにアスタリスク()を使用することをサポートしています。あなたが書いているシナリオに何かを列挙しようとするとき、あなたはそれを自然言語における箇条書きのように表現することができます。アスタリスク()を使用しないのであればAndキーワードなどを使うこともできますが、これはエレガントではないかもしれません。

例:

sample_asterisk1.feature
Scenario: All done
  Given I am out shopping
  And I have eggs
  And I have milk
  And I have butter
  When I check my list
  Then I don't need anything

これは、以下のように表現することができます:

sample_asterisk2.feature
Scenario: All done
  Given I am out shopping
  * I have eggs
  * I have milk
  * I have butter
  When I check my list
  Then I don't need anything

Background

時折、Feature内のすべてのシナリオで同じGivenステップを繰り返ていることに気づくでしょう。
これはすべてのシナリオで繰り返されるものであるため、つまりそのステップはシナリオに記述する必要があるとは言えません。それらはすべて同一の内容だからです。このような場合、これらのGivenステップをBackgroundセクションに移動することができます。
Backgroundは、シナリオがフォローすべき文脈を追加します。Backgroundには1つ以上のGivenステップを追加することができ、これらはシナリオの最初に実行されます(より正確には、Beforeホック→Backgroundキーワード内のGivenステップ→シナリオ内のステップの順で実行されます)。
Background は最初のScenarioまたはExampleの前に記述されます。インデントのレベルはどれも同じです。
【参考】Beforeホックの説明と、Backgroundキーワードとの違い:Cucumber | @Before hook Vs Background | Usage

サンプル:

background_sample1.feature
Feature: Multiple site support
  Only blog owners can post to a blog, except administrators,
  who can post to all blogs.

  Background:
    Given a global administrator named "Greg"
    And a blog named "Greg's anti-tax rants"
    And a customer named "Dr. Bill"
    And a blog named "Expensive Therapy" owned by "Dr. Bill"

  Scenario: Dr. Bill posts to his own blog
    Given I am logged in as Dr. Bill
    When I try to post to "Expensive Therapy"
    Then I should see "Your article was published."

  Scenario: Dr. Bill tries to post to somebody else's blog, and fails
    Given I am logged in as Dr. Bill
    When I try to post to "Greg's anti-tax rants"
    Then I should see "Hey! That's not your blog!"

  Scenario: Greg posts to a client's blog
    Given I am logged in as Greg
    When I try to post to "Expensive Therapy"
    Then I should see "Your article was published."

Backgroundは、Ruleレベルに記述することもできます:

background_sample2.feature
Feature: Overdue tasks
  Let users know when tasks are overdue, even when using other
  features of the app

  Rule: Users are notified about overdue tasks on first use of the day
    Background:
      Given I have overdue tasks

    Example: First use of the day
      Given I last used the app yesterday
      When I use the app
      Then I am notified about overdue tasks

    Example: Already used today
      Given I last used the app earlier today
      When I use the app
      Then I am not notified about overdue tasks
  ...

Backgroundは、FeatureまたはRuleごとに1つだけ定義することができます。異なるシナリオに異なるBackgroundが必要な場合は、シナリオをより細かいRuleFeatureに分解することを考えた方が良いでしょう。

より明示的でないBackgroundの代替物に関しては、conditionalホックをチェックするとよいです。

Backgroundを使う際のTips

  • Backgroundを複雑な状態で使用しない、クライアントがその状態を知る必要がない限りは
    • 例えば、もしユーザー名とサイト名がクライアントにとって問題でなければ、Given I am logged in as a site ownerのようなハイレベルなステップを使用します
  • Backgroundセクションを短くする
    • クライアントはシナリオを読むとき、バックグラウンドの内容を覚えておく必要があります。もしBackgroundが4行以上で構成されている場合は、関連しないものをハイレベルのステップに移動することを検討したほうがよいでしょう
  • Backgroundセクションを鮮明にする
    • カラフルな名前を使い、ストーリーを伝えるように努めます。人間の脳は"User A", "User B", "Site 1"のような名前よりも、ストーリーのほうが覚えやすいからです
  • シナリオを短くし、あまり多すぎるようにはしない
    • Backgroundセクションがスクリーン外になるまでスクロールされると、読み手はBackgroundセクションで何が起きるのかすべて把握できなくなります。この場合、ハイレベルなステップを利用するか、*.feature ファイルに分割することを検討するとよいでしょう

Scenario Outline

Scenario Outlineキーワードは、同じシナリオを別々の値を使って実行したいときに使用します。
Scenario TemplateキーワードはScenario Outlineキーワードの同義語です。
異なる値を使用するためにシナリオをコピー&ペーストするのは退屈ですし反復的です:

sample_scenario_outline1.feature
Scenario: eat 5 out of 12
  Given there are 12 cucumbers
  When I eat 5 cucumbers
  Then I should have 7 cucumbers

Scenario: eat 5 out of 20
  Given there are 20 cucumbers
  When I eat 5 cucumbers
  Then I should have 15 cucumbers

このとき、私たちは2つの似通ったシナリオを1つのScenario Outlineにcollapseすることができます。
Scenario Outlineでは< >-delimited parameterを使用したtemplateを記述することができ 、これによって複数のシナリオを簡潔に表現することができます:

sample_scenario_outline2.feature
Scenario Outline: eating
  Given there are <start> cucumbers
  When I eat <eat> cucumbers
  Then I should have <left> cucumbers

  Examples:
    | start | eat | left |
    |    12 |   5 |    7 |
    |    20 |   5 |   15 |

Scenario Outlineは、Example(またはScenario)セクションを含まなければなりません。ステップは直接実行されることのないtemplateとして解釈されます。その代わり、Scenario OutlineExampleセクションの行数の分だけ実行されます(ヘッダー行を除く)。
ステップでは、Exampleテーブルのヘッダー行を参照する<> delimited parametersを使用することができます。Cucumber では、ステップとstep definitionをマッチする前にこれらのパラメータをテーブルの値に置換します。
また、パラメータをmultiline step argumentsで使用することもできます。

Step Arguments

幾つかのケースでは、あなたはステップに対して1行では収まらないデータを渡す必要があるかもしれない。この目的のため、GherkinにはDoc StringsData Tablesがある。

Doc Strings

Doc Stringsは大きな量のテキストをstep definitionに渡すときに便利です。
テキストは、3つのダブルクオーテーションで区切る必要があります:

sample_doc_strings1.feature
Given a blog post named "Random" with Markdown body
  """
  Some Title, Eh?
  ===============
  Here is the first paragraph of my blog post. Lorem ipsum dolor sit amet,
  consectetur adipiscing elit.
  """

step definitionにおいて、このテキストを見つける必要もなければあなたのパターンにマッチする必要もありません。自動的に、step definitionの最後の引数として渡されます。
最初の"""のインデントは重要ではないものの、一般的にはenclosing stepからスペース2つ分インデントします。しかし、"""の内側に関しては、インデントは重要です。Doc Stringのそれぞれの行は、開始の"""を参考にしてdedented されます。したがって、開始の"""以降の行のインデントは保存されます。
また、Doc stringsはデリミタとして3つのbackticks をサポートしています:

sample_doc_strings2.feature
  Given a blog post named "Random" with Markdown body
    ```
    Some Title, Eh?
    ===============
    Here is the first paragraph of my blog post. Lorem ipsum dolor sit amet,
    consectetur adipiscing elit.
    ```

Data Tables

Data Tablesは、step definitionに値の一覧を渡すときに便利です:

sample_data_tables1.feature
Given the following users exist:
  | name   | email              | twitter         |
  | Aslak  | aslak@cucumber.io  | @aslak_hellesoy |
  | Julien | julien@cucumber.io | @jbpros         |
  | Matt   | matt@cucumber.io   | @mattwynne      |

Doc Stringsのように、Data Tablesは最後の引数としてstep definitionに渡されます。
Cucumberは、テーブルをstep definitions内から操作するAPIを提供しています。詳細についてはData Table API referenceを参照してください。

Spoken Languages

Gherkinで使用する言語は、あなたのユーザーやdomain expertsがドメインについて会話するときに用いる言語であるべきです。2つの言語を翻訳しなければならなない状態は避けるべきでしょう。
そのため、Gherkinは70を超える言語に翻訳されています。
以下に示すのは、シナリオをノルウェー語で記載したものです:

sample_spoken_languages.feature
# language: no
Funksjonalitet: Gjett et ord

  Eksempel: Ordmaker starter et spill
    Når Ordmaker starter et spill
    må Ordmaker vente på at Gjetter blir med

  Eksempel: Gjetter blir med
    Gitt at Ordmaker har startet et spill med ordet "bløtt"
    Når Gjetter blir med på Ordmakers spill
    må Gjetter gjette et ord på 5 bokstaver

1行目の# language:ヘッダが、Cucumberに使用する言語を伝えます。例えば、# language: frはフランス語です。# language:ヘッダを記述しなかった場合は、Cucumberはデフォルト設定の英語を使用します。
いくつかのCucumber implementationsは設定でデフォルト言語を決めることができます。その際は、すべてのファイルで# language:ヘッダを記述する必要はありません。

19
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
10