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

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

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

```gherkin: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キーワードから始める必要があります。ただし、`Feature`と`Scinario`に対して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フォーマッタ）。

```gherkin: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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77762/0b6583df-dae8-e290-9237-7b76303a671b.jpeg)

### 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つ以上のシナリオから構成されます。

例：

```gherkin: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は、以下のステップを複製であると認識します：

```gherkin:step_sample1.feature
Given there is money in my account
Then there is money in my account
```

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

```gherkin: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`を連続して記述したいとき、次のように書くことができるでしょう：

```gherkin: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`, `Then`を`And`, `But`に置換して、`Example`をfluidly structuredな形にすることもできます：

```gherkin: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`キーワードなどを使うこともできますが、これはエレガントではないかもしれません。

例:

```gherkin: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
```
これは、以下のように表現することができます：

```gherkin: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](https://medium.com/@priyank.it/cucumber-before-hook-vs-background-usage-f10453e81920)

サンプル：

```gherkin: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`レベルに記述することもできます：

```gherkin: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`ごとに１つだけ定義することができます。異なるシナリオに異なる`Background`が必要な場合は、シナリオをより細かい`Rule`や`Feature`に分解することを考えた方が良いでしょう。

より明示的でない`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`キーワードの同義語です。
異なる値を使用するためにシナリオをコピー＆ペーストするのは退屈ですし反復的です：

```gherkin: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を記述することができ 、これによって複数のシナリオを簡潔に表現することができます：

```gherkin: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 Outline`は`Example`セクションの行数の分だけ実行されます（ヘッダー行を除く）。
ステップでは、`Example`テーブルのヘッダー行を参照する<> delimited parametersを使用することができます。Cucumber では、ステップとstep definitionをマッチする前にこれらのパラメータをテーブルの値に置換します。
また、パラメータをmultiline step argumentsで使用することもできます。

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

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

```gherkin: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 をサポートしています：

```gherkin: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に値の一覧を渡すときに便利です：

```gherkin: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](https://github.com/cucumber/common/tree/master/datatable)を参照してください。

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

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

  Eksempel: Ordmaker starter et spill
    Når Ordmaker starter et spill
    Så 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
    Så må Gjetter gjette et ord på 5 bokstaver
```
1行目の`# language:`ヘッダが、Cucumberに使用する言語を伝えます。例えば、`# language: fr`はフランス語です。`# language:`ヘッダを記述しなかった場合は、Cucumberはデフォルト設定の英語を使用します。
いくつかのCucumber implementationsは設定でデフォルト言語を決めることができます。その際は、すべてのファイルで`# language:`ヘッダを記述する必要はありません。