Karate を使ったWebサービス テスト その１


## Karate とは？

シンプルな記述でWebサービスのテストを行えるテストフレームワークです。

https://github.com/intuit/karate

## 記述例

Cucumber JVMの上で動いており、Gherkin文法で記載します。

```gherkin
Feature: karate 'hello world' example
Scenario: create and retrieve a cat

Given url 'http://myhost.com/v1/cats'
And request { name: 'Billie' }
When method post
Then status 201
And match response == { id: '#notnull', name: 'Billie' }

Given path response.id
When method get
Then status 200
```

これを実行すると
1. `http://myhost.com/v1/cats` に `{"name": "Billie"}` のPOSTリクエストを行う
2. レスポンスのstatusが201であることを確認
3. レスポンスのデータとして、 `{"id": なにかはいってる, "name": "Billie"}` であることを確認
4. さっき取得した、レスポンスのデータのidの値を利用して、`http://myhost.com/v1/cat/[idの値]` にGETリクエストを行う
5. レスポンスのステータスが200 であることを確認

といった流れです。

日本語での説明文より、DSLをそのまま見た方が頭にすっとはいってくるぐらい簡潔に可読性よくかけます。（~~日本語が下手なだけも...~~）


## 実行してみる

READMEには、複数の方法（実行方法、レポート）が書いてありますが、ここでは、実行はgradle、 テストシナリオは並列実行、Cucumberレポートで結果を確認する形式で行なっています。


ソースは以下にあります。
https://github.com/ihgs/karate-sample/tree/sample%231/


フォルダ構造

```
karate-sample
├── build.gradle
└── src
    └── test
        └── java
            ├── TestParallel.java
            ├── karate-config.js
            ├── logback-test.xml
            └── qiita
                └── qiita.feature
```


### [TestParalle.java](https://github.com/ihgs/karate-sample/blob/sample%231/src/test/java/TestParallel.java)

Junitのテストケースになっています。

５並列でシナリオを実行し、Cucumberレポートを作成します。
この形式では、`@RunWith(Karate.class)`をつけないことに注意してください。

### [karate-config.js](https://github.com/ihgs/karate-sample/blob/sample%231/src/test/java/karate-config.js)

設定ファイルです。
ここで、ProxyやConnection Timeout の設定、各feature で利用する共通の変数とかを定義できます。

### [logback-test.xml](https://github.com/ihgs/karate-sample/blob/sample%231/src/test/java/logback-test.xml)

ログの設定です。なくても動きます。

### [qiita.feature](https://github.com/ihgs/karate-sample/blob/sample%231/src/test/java/qiita/qiita.feature)

テストシナリオです。
以下の３つのシナリオを定義しています。

#### 1. シンプルなシナリオ
ihgsユーザーの投稿を５件取得し、結果が５件かどうか確認しています。

#### 2. `Scenario Outline`と`Examples`を利用したシナリオ
投稿idを指定しGetしており、各idごとに取得できた投稿タイトルが一致しているか確認しています。
Examplesで指定した列ごとに、変数展開されたうえで実行されます。

#### 3. タグを指定したシナリオ
シナリオの前に、`@xxxx` とすることでタグ付けできます。ignoreタグとfailcaseタグの２つを指定しています。ちなみに、Featureの前に指定すると、そのファイルのシナリオ全てにそのタグが有効になります。


Background は、各シナリオでの共通の前処理を書きます。
ここでは、urlに、karate-config.js で設定した値をセットしています。


### 実行

以下を実行することで、1と2のシナリオが実行されます。
3は、TestParalle.java で、ignore以外と指定している(`@CucumberOptions(tags = {"~@ignore"})`)ため実行されません。

```
gradle clean test
```

実行時にcucumber.optionsを設定することで、設定の上書きを行えます。

```
gradle clean test -Dcucumber.options="--tags @failcase"
```

failcaseタグがついているシナリオ3だけ実行されます。


### 結果

`build/karate/cucumber-html-reports` 以下に結果が出力されています。

![karate-overview.png](https://qiita-image-store.s3.amazonaws.com/0/51316/fa4312ec-8dd5-f898-7271-c40bd54514f3.png)


各シナリオのステップごとの様子を確認でき、リクエストの詳細も確認できます。

![karate-scenario.png](https://qiita-image-store.s3.amazonaws.com/0/51316/cdd8eedf-ba55-7b26-0267-aa995db250a3.png)

![karate-get.png](https://qiita-image-store.s3.amazonaws.com/0/51316/3012d46f-e1fa-4758-dac1-74ae6252f552.png)


`print response` を記述しておけば、整形されたjsonが出力されます。
(今回の例だとrendered_bodyの値が大きいので、あまり整形された感は出ませんが...。画像は、rendered_bodyの途中から切り取ったものです。)

![karate-print.png](https://qiita-image-store.s3.amazonaws.com/0/51316/6d55e4b0-549a-83f3-7bb9-20c161583786.png)



## 最後に

機能が豊富でまだほとんど試せていませんが、簡単なテストなら説明した機能だけで十分実装できる感じです。

ポーリングなどは、少し工夫がいったので、次回はそこらへんを書いていこうかと思います。


なお、バージョンが浅いこともあり(v0.6.1)、バージョンアップごとにBreaking Change（破壊的変更）があることが多いです。利用する際はご注意ください（[リリース情報](https://github.com/intuit/karate/releases)にどこが変わったかはきちんと記述されています )