Enterprise APIs Advent Calendar 2015の一回目ということでどのネタにしようかいろいろ考えましたが、以前紹介したREST API用テストフレームワークまとめのapickli/apickli検証ネタを書きます。
Enterprise APIs Advent Calendar 2015
apickli/apickli
Cucumberフレームワークという、Behaviour-Driven Development (BDD)を実現するフレームワークです。システムテストにおいて受け入れテストに向いている自動化フレームワークです。
apickliは、Cucumberフレームワークをnode.jsで実装したcucumber.jsを活用、自然言語シナリオをもとにREST APIのリクエストに対して期待値のレスポンスをOK/NGをテスト可能。
Given(前提)、When(もし)、Then(ならば)、and(かつ)、but(しかし)を組み合わせでテストシナリオを書いてきます。
事前準備
適当な環境(linux,macなど)でGitHubから環境をとってきます。 node.jsはnvmなどで稼働できるようにしておくとよいです。
では手順にしたがって準備していきます。
node.js install
npm install -g cucumber
apickliをダウンロード
git clone https://github.com/apickli/apickli.git
サンプルプロジェクトの確認
cd apickli/example-project/test
tree
.
└── features
├── fixtures
│ └── requestBody.xml
├── httpbin.feature
└── step_definitions
├── apickli-gherkin.js -> ../../../node_modules/apickli/apickli-gherkin.js
└── httpbin.js
という構成になっていると思います。
package.json編集
cd ..
cat package.json
{
"name": "httpbin-test",
"version": "1.0.0",
"description": "Integration testing for myapi with httpbin.org",
"dependencies": {
"apickli": "latest"
}
}
上記のように編集します。nameのところは、httpbinを活用したテストなのでこれでよいです。 httpbinとは、REST APIで取り急ぎ、サンプルリクエストに対し、レスポンスを提供してくれる便利な無料APIになっています。
依存関係のモジュールをインストール
npm install
package.jsonの置いてるところで、本コマンドを実施してください。 これで依存関係のモジュールがインストールされます。
サンプルシナリオの宛先確認
cd apickli/example-project/test/features/step_definitions
vi httpbin.js
//中略
this.apickli = new apickli.Apickli('http', 'httpbin.org');
このファイルにテストしたいAPIの宛先を書きます。 まずは、デフォルトのままでよいです。
サンプルシナリオの実行
これでfeatures/httpbin.featureに書かれているシナリオに従って実行されていきます。 とりあえず実行してみましょう。
cd apickli/example-project/test
cucumber-js features/httpbin.feature
テストの標準出力結果一部
Feature:
Httpbin.org exposes various resources for HTTP request testing
As Httpbin client I want to verify that all API resources are working as they should
Scenario: Setting headers in GET request # features/httpbin.feature:5
Given I set User-Agent header to apickli # ../node_modules/apickli/apickli-gherkin.js:6
When I GET /get # ../node_modules/apickli/apickli-gherkin.js:31
Then response body path $.headers.User-Agent should be apickli # ../node_modules/apickli/apickli-gherkin.js:153
Scenario: Setting body payload in POST request # features/httpbin.feature:10
Given I set body to {"key":"hello-world"} # ../node_modules/apickli/apickli-gherkin.js:11
When I POST to /post # ../node_modules/apickli/apickli-gherkin.js:41
Then response body should contain hello-world # ../node_modules/apickli/apickli-gherkin.js:137
(中略)
Failing scenarios:
features/httpbin.feature:25 # Scenario: Setting body payload from file
24 scenarios (1 failed, 1 ambiguous, 22 passed)
70 steps (1 failed, 2 ambiguous, 2 skipped, 65 passed)
0m13.164s
The following steps have multiple matching definitions:
"I subtract remaining2 from remaining1" matches:
/^I subtract (.*) from (.*)$/ # features/step_definitions/apigw.js:16
/^I subtract (.*) from (.*)$/ # features/step_definitions/httpbin.js:16
"result should be 1" matches:
/^result should be (\d+)$/ # features/step_definitions/apigw.js:24
/^result should be (\d+)$/ # features/step_definitions/httpbin.js:24
という感じで、出力されます。一部エラーが出てますね。
テストのオプション
Usage: cucumber-js [options] [<DIR|FILE[:LINE]>...]
Options:
-h, --help output usage information
-v, --version output the version number
-b, --backtrace show full backtrace for errors
--compiler <EXTENSION:MODULE> require files with the given EXTENSION after requiring MODULE (repeatable)
-d, --dry-run invoke formatters without executing steps
--fail-fast abort the run on first failure
-f, --format <TYPE[:PATH]> specify the output format, optionally supply PATH to redirect formatter output (repeatable)
--no-colors disable colors in formatter output
--no-snippets hide step definition snippets for pending steps
--no-source hide source uris
-p, --profile <NAME> specify the profile to use (repeatable)
-r, --require <FILE|DIR> require files before executing features (repeatable)
--snippet-syntax <FILE> specify a custom snippet syntax
-S, --strict fail if there are any undefined or pending steps
-t, --tags <EXPRESSION> only execute the features or scenarios with tags matching the expression (repeatable)
For more details please visit https://github.com/cucumber/cucumber-js#cli
の感じで、タグ指定なんかを使うとシナリオテストをブロックごとにタグ分けしておくとそこの部分だけテストができます。
cucumber-js features/httpbin.feature --tags @token
Feature:
Httpbin.org exposes various resources for HTTP request testing
As Httpbin client I want to verify that all API resources are working as they should
@token
Scenario: Access token retrieval from response body (authorization code grant, password, client credentials) # features/httpbin.feature:81
Given I set Token header to token123 # ../node_modules/apickli/apickli-gherkin.js:6
When I GET /get # ../node_modules/apickli/apickli-gherkin.js:31
Then I store the value of body path $.headers.Token as access token # ../node_modules/apickli/apickli-gherkin.js:169
@token
Scenario: Using access token # features/httpbin.feature:87
Given I set bearer token # ../node_modules/apickli/apickli-gherkin.js:174
When I GET /get # ../node_modules/apickli/apickli-gherkin.js:31
Then response body path $.headers.Authorization should be Bearer token123 # ../node_modules/apickli/apickli-gherkin.js:153
2 scenarios (2 passed)
6 steps (6 passed)
0m01.104s
こんな感じです。 シナリオの記述の仕方は、Cucumberのfeatureファイルのプラクティスにもありますが、
given (code) | "前提"
when (code) | "もし"
then (code) | "ならば"
and (code) | "かつ" |
but (code) | "しかし", "但し", "ただし"
をうまく組み合わせすることで、様々な受け入れテストのパターン分岐のシナリオを記述することができると思います。
apickliで最初から準備されてる便利なところ
基本、test/featuresの*.featureファイルに自然言語にてシナリオを記述し、そのシナリオに従ったコードを、test/features/step_definitions配下にモジュールを記述していきます。
test/features/step_definitions/apickli-gherkin.jsがライブラリ的に最初から用意されているので、
I set body to {"key":"hello-world"}
I POST to /post
response body should be valid json
response header boo should not exist
response body should contain WonderWidgets
などのようなリクエスト、レスポンスの中身チェックが簡単にできるところが、非常にテストに有益と思います。
これで、JenkinsなどのCIツールと組み合わせすれば、APIサーバモジュールリリースに合わせて、シナリオ自動テストができますね。 別途、Jenkins+Docker+cucumber.jsでやってみたいと思います。
REST APIの受け入れテストは、まだまだこれからベストプラクティスが出てくるかと思いますが、他にも良いフレームワークがあれば、実際に使って紹介していきたいと思います。