Yaml書くだけでWebAPIのテストができるツールつくった

どうも。

WebAPIのテストを、PHPUnitやCodeceptionとか使わないでしたいって要望が周辺からあがったんでライブラリを作りました。　

https://github.com/cloudpack/Rorschach
https://packagist.org/packages/cloudpack/rorschach


# Rorschach (ロールシャッハ)
ライブラリの名前です。この名前超気に入ってます。

* 絶対に妥協しないアメコミヒーローのロールシャッハ
* シミ？をみる有名な性格診断テスト

の意味合いが決め手となり、社内でのコンペを勝ち上がった名前です。かっこいい。
Guzzleとsymfony/consoleベースです。

# 使い方
READMEよんでって言いたいんですけど怒られそうなんで書きます。


## インストール

```
# composerをインストール
curl -S https://getcomposer.org/installer | php

# Rorshachをインストール
php composer.phar require --dev cloudpack/rorschach
```

例によって、 `vendor` 以下にライブラリがインストールされます。


## 実行

```
composer exec rorschach inspect
```

## 構文

```test-orenotest.yml
base: https://(( env )).example.com
headers:
  x-api-key: YOUR-SECRET-KEY
  ContentType: application/json
allow_redirects: 
    max: 5
    strict: false
    referer: false
    protocols:
      - http
      - https
    track_redirects: false
pre-requests:
  -
    resource: /auth
    method: GET
    headers:
      x-header: HEADER
    body:
      name: shinichi
      password: p@ssw0rd
    bind:
      api-token: response.data.param
resources:
  -
    url: /users
    method: GET
    headers:
      api-token: (( api-token ))
    body:
      exclude: false
    expect:
      code: 200
      has:
        - id
        - user.name
        - user.address..tel01
      assert:
        id: integer|nullable
        name: string
  -
    url: /items
    method: GET
    expect:
      code: 302
      redirect: https://prod.example.com
```

### base句
* base: テスト対象のAPIのURLを指定 _(必須)_

### header句
* headers: 全てのリクエストに付与するHTTP headerを指定

### allow_redirects句
* リダイレクトに関する設定を行う。
* [Guzzleのドキュメント](http://docs.guzzlephp.org/en/latest/request-options.html#allow-redirects) を参照ください。

### pre-requests句
* resource: テストをしたいリソースを指定
* method: methodを指定 (GET, POST, PUT, DELETE, PATCH ...)
* body: テスト時に送るbody部を記載
* bind: レスポンスから変数に代入したい値と、変数名を記載（後述）

### resources句
* resources: テストするリクエストを定義 _(必須)_
* resources.url: テストをしたいリソースを指定
* resources.method: methodを指定 (GET, POST, PUT, DELETE, PATCH ...)
* resources.body: テスト時に送るbody部を記載
* resources.expect: レスポンスから期待する型、status codeなどを記載
    + code: レスポンスのstatus codeが同値であるかを判定
    + has: 列挙したキー名が存在するかを判定  
      探査可能
    + assert: 列挙したキー名に該当する値の型が妥当かを判定（integer, string, nullable, array)  
     探査可能
    + redirect: リダイレクト先が正しいか判定（allow_redirects句の設定が必要）

### 探査可能とは？
探査可能なオプションでは、（ `resources.expect.has` や `resources.expect.assert` ）は、以下のようにオブジェクトや配列を柔軟に探査することができます。

`a.b` の場合

```tansa.json
{
  "a": {
    "b": "object:aの中の、key:bを探査"
  }
}
```

`a..b` の場合

```tansa.json
{
  "a": [
    {
      "b": "object:aの中の、配列の最初の要素の中の、key:bを探査"
    }
  ]
}
```


## オプション

### --file
プロジェクトのルート・ディレクトリにある `test*.yml` を勝手に取りに行ってパースしてテスト流し始めます。
特定ファイルだけのテストをしたい場合は、 `--file` オプションを指定してください。

```
./vendor/cloudpack/rorschach/console inspect --file='test-orenotest.yml
```

### --bind -b

`(( ))` ブラケットを記載することで、変数を外部から設定できます。
コマンドライン引数として設定するコマンドインジェクション方式と、pre-requestsのresponseから設定するプリリクエスト方式の２つの方法で設定が可能です。

#### コマンドインジェクション方式

例えば、

```
https://abc.example.com
https://xyz.example.com
```

のようにAPIのサブドメインを変えてテストしたい場合は、

```
https://(( env )).example.com
```

と、 `(( ))` ブラケットで囲い、コマンドライン引数から設定することで柔軟に対応が可能です。

```test-orenotest.yml
base: https://(( env )).example.com
...
```

```
./vendor/cloudpack/rorschach/console inspect --bind='{"env": "abc"}'
```

#### プリリクエスト方式
pre-requests句を使うことで、続くリクエストに認証が必要な場合に、レスポンスから変数に値を代入できます。
pre-requests句は、基本文法の `resources` とほぼ書き方は一緒で、 `bind` 句が追加されます。

`/auth` に対して認証を行い、responseからapi-tokenを取得する場合は以下のようにします。

```test-orenotest.yml
pre-requests:
  -
    resource: /auth
    method: GET
    body:
      name: shinichi
      password: p@ssw0rd
    bind:
      api-token: response.data.param
```

bind構文では、responseを探査する仕組みを実装しています。
`response.data.param` とした場合、 `(( api-token ))` 変数に以下の `API-TOKEN` が代入されます。

```response.json
{
  "response": {
    "data": {
      "param": "API-TOKEN"
    }
  }
}
```


# 最後に
まだ実践導入してないので、どなたかご利用頂いた上でご意見いただけると超うれしいです！
ダメ出しプルリク大歓迎！文句も受け付けます。リファクタも随時すすめていきます。