※KDDIコマースフォワード㈱ 、略称「KCF」は2019年4月1日、同グループ会社の㈱ルクサと合併し「auコマース&ライフ株式会社」として再設立いたしました。 本記事は2019年3月31日以前に書かれた記事のアーカイブとなります。予めご了承ください。
はじめまして。エンジニアの河野です。
最近、担当しているプロダクトのリグレッションテストを実施しようとしていて、何か良いツールないかと探した結果、Robot Frameworkを使ってみることにしました。
やりたいことはとりあえずWeb APIのシナリオテスト的なものを実施したかったので、RESTinstanceというプラグインを使うと記述が楽そうだったのでこちらも一緒に利用してみました。
そちらも絡めて軽くレポートさせて頂きます。
インストール手順
基本的に公式サイトにドキュメントへのリンクがまとまっているので、インストールからデモ動作まではこちらから各種ドキュメント見て頂くのが良いと思いますが、ざっと説明しておきます。
今回はpipでインストールするのでpipは必須となります。
自分はDocker上のUbuntuコンテナに入れたので、以下をDockerfileに記述しておきました。
Robot Framework自体はプロセスではないのですが、ローカルマシンにあれこれ入れたくないのとローカル用の開発環境もDokcerなので検証しやすかったので。
日本語使いたかったのでlanguage-packも入れています。
- Dockerfile
FROM ubuntu:18.04 MAINTAINER kcf.kono ENV DEBIAN_FRONTEND=noninteractive # install packages RUN apt-get update RUN apt-get install -y git python3-pip # install additional packages RUN apt-get install -y tzdata locales language-pack-ja-base language-pack-ja # setting RUN locale-gen ja_JP.UTF-8 RUN mkdir /sync ENV LANG=ja_JP.UTF-8 # install robot framework RUN pip3 install docutils robotframework RUN pip3 install --upgrade RESTinstance
Robot FrameworkとRESTinstanceのインストール部分はこちらになります。
RUN pip3 install docutils robotframework RUN pip3 install --upgrade RESTinstance
とりあえず動かしてみる
QuickStartGideがあるので、そちらをGitHubから持ってきて動作させてみます。
$ git clone https://github.com/robotframework/QuickStartGuide.git
QuickStart.rstというreStructuredText形式のファイルがあって読んでみると、直接そのファイルを指定して実行することが出来る様です。
ただ、拡張子が.robot以外のファイルは非推奨と警告でるので、自分でテストケース作る場合はrobotファイルを作ってそちらに記述してます。
$ robot QuickStart.rst [ WARN ] Automatically parsing other than '*.robot' files is deprecated. Convert '/sync/QuickStartGuide/QuickStart.rst' to '*.robot' format or use '--extension' to explicitly configure which files to parse. ============================================================================== QuickStart ============================================================================== User can create an account and log in | PASS | ------------------------------------------------------------------------------ User cannot log in with bad password | PASS | ------------------------------------------------------------------------------ User can change password | PASS | ------------------------------------------------------------------------------ Invalid password | PASS | ------------------------------------------------------------------------------ User status is stored in database | PASS | ------------------------------------------------------------------------------ QuickStart | PASS | 5 critical tests, 5 passed, 0 failed 5 tests total, 5 passed, 0 failed ============================================================================== Output: /sync/QuickStartGuide/output.xml Log: /sync/QuickStartGuide/log.html Report: /sync/QuickStartGuide/report.html
実行後にはxmlとhtmlが出力され、htmlファイルを開くと結果レポートが表示されます。
結果レポートのスクリーンショットがこちらのEXAMPLE 2に載っているので参考になるかと思います。
テストケースを記述してみる
まずは簡単なテストケースを記述してみることにします。
今回はWeb APIのテストを行いたいので、RESTinstanceを利用してヘルスチェック用APIへのテストを実行してみようと思います。
ヘルスチェック用APIはHTTPステータス 200を返すだけのものとなります。
*** Settings *** Library REST https://example.com *** Test Cases *** リクエストを送るとHTTP STATUS 200が返ってくる GET /health_check Integer response status 200
Robot FrameworkはPythonで出来ていて、テストケースの記述方法もPythonに習ってテーブル形式で記述します。
「*** Settings ***」テーブルにはインポートするライブラリを記述します。
今回はRESTinstanceを利用するのでRESTと指定しています。
RESTの後に接続するURLを指定が出来、アクション実行時にURLを省略することが出来ます。
指定しない場合はアクセスの都度指定することになります。
「***Test Cases ***」テーブルに実際のアクションを記述します。
行頭にインデント入れていない部分がテストケースのタイトルになります。
Python3使っているからか普通に日本語は使えました。
アクションは行頭にインデント入れて字下げした箇所に記述します。
GET [PATH]で、[PATH]に対してGETリクエストして
Integer [検証対象] [期待値] でHTTPステータスが200で返ってくることを検証しています。
実行すると以下の様になります。
============================================================================== Health Check :: RESTinstanceのサンプル用にヘルスチェック用APIのリクエストを... ============================================================================== [ WARN ] Response body content is not JSON. Content-Type is: text/plain; charset=utf-8 リクエストを送るとHTTP STATUS 200が返ってくる | PASS | ------------------------------------------------------------------------------ Health Check :: RESTinstanceのサンプル用にヘルスチェック用APIのリ... | PASS | 1 critical test, 1 passed, 0 failed 1 test total, 1 passed, 0 failed ============================================================================== Output: /sync/tests/output.xml Log: /sync/tests/log.html Report: /sync/tests/report.html
ヘルスチェックのResponse Bodyが空文字列なので、Warning出ていますがとりあえずテストをパスしました。
RESTinstanceの良いところはHTTPリクエストのテストケースをシンプルに記述出来るところで、同じHTTPリクエスト系のライブラリのrobotframework-requestsを使うと以下の様に若干めんどくさくなります。
*** Settings *** Documentation robotframework-requestsのサンプル用にヘルスチェック用APIのリクエストを記述 Library RequestsLibrary *** Test Cases *** リクエストを送るとHTTP STATUS 200が返ってくる Create Session sample https://example.com verify=True ${resp}= Get Request sample /health_check Should Be Equal As Strings ${resp.status_code} 200
もう少し凝ったテストをしてみる
実際のシナリオテストとなるともう少し凝ったことをするケースがあるので、以下をやってみました。
これをテストケースとして記述してみます。
*** Settings *** Library REST *** Variables *** ${api_url} https://example.com ${auth_url} https://auth.example.com ${auth_api_key} api_key_1 ${auth_header} {"x-api-key": "${auth_api_key}"} ${auth_json} {"id": 1 , "credential_key": "qazxswedcvfr"} *** Test Cases *** ログインしてデータ一覧取得 Set headers ${auth_header} &{auth_response} POST ${auth_url}/loginauth ${auth_json} Output ${auth_response.body.token} Set headers {"x-auth-token": "${auth_response.body.token}"} &{response} GET ${api_url}/resources Integer response status 200 String ${response.body[0].name} "テストデータ"
上記のテストケースですが、新たに「*** Variables ***」というテーブルを追加しています。
こちらでは上記の様に変数を定義することが出来ます。
また、「*** Test Cases ***」テーブルの中でも結果を変数に代入することが可能です。
これでリクエストの結果を利用して他のリクエストを実行することなどが出来ます。
変数の宣言方法は以下があるようです。
RESTinstanceのサンプルから引用します。
${json}= {"foo": "bar" } # JSON object, represented as Python str &{dict}= foo=bar # Python dict, corresponds to JSON object ${array}= ["foo", "bar"] # JSON array, represented as Python str @{list}= foo bar # Python list, corresponds to JSON array
${VARIABLE}で定義するとスカラ変数(String)となりますが、&{VARIABLE}で定義すると辞書変数(Object)になるのでJSON形式のレスポンスに${auth_response.body.token}のようにアクセスすることも出来ます。
RESTinstanceの場合は$自体がresponse bodyと等価の様なので、以下の様に記述することも可能です。
...省略 *** Test Cases *** ログインしてデータ一覧取得 Set headers ${auth_header} &{auth_res} POST ${auth_url}/loginauth ${auth_json} Output $.token Set headers {"x-auth-token": "${auth_res.body.token}"} &{response} GET ${api_url}/resources Integer response status 200 String $[0].name "テストデータ"
外部ファイル読み込み
「*** Variables ***」テーブルの内容を別ファイルにし、以下のように外部ファイルをincludeすることも出来ます。
- common.robot
*** Variables *** ${api_url} https://example.com ${auth_url} https://auth.example.com ${auth_api_key} api_key_1 ${auth_header} {"x-api-key": "${auth_api_key}"} ${auth_json} {"id": 1 , "credential_key": "qazxswedcvfr"}
- sample.robot
*** Settings *** Library REST Resource common.robot ...省略
上記のように「*** Settings ***」テーブルでResource [PATH]とすることで外部ファイルを読み込む事ができるので、テストファイル毎に重複する様な場合に効率的です。
環境変数
環境変数も取り込むことが可能です。
リポジトリに上げたくない様な機密情報はOSの環境変数に設定して、参照することでテストケースへの記述を回避することが出来ます。
環境変数は%{VARIABLE}で参照出来ます。
設定例としては以下になります。
$ export AUTH_API_KEY=api_key_1 $ cat common.robot *** Variables *** ${api_url} https://example.com ${auth_url} https://auth.example.com ${auth_api_key} %{AUTH_API_KEY} ${auth_header} {"x-api-key": "${auth_api_key}"} ${auth_json} {"id": 1 , "credential_key": "qazxswedcvfr"}
変数についてはこちらにドキュメントがまとまっています。
日本語翻訳版があるのが英語の得意でない自分にはありがたいですね。
まとめ
今回は簡単なWeb APIのシナリオテストを作って実施してみました。
使ってみた感想としては以下になります。
良かったところ
- DSLが直感的で分かりやすい
- 機能が豊富なため細かい制御が可能
- 出来るといいなが大抵用意されている
- ドキュメントが充実している
- RESTinstanceは記述を楽にしてくれる
良くなかったところ
- テーブルのインデント調整がめんどくさい (面合わせなくてもいいのですが合わせないと見にくいので。フォーマッターで解決出来そうですが。)
- RESTinstanceのスター数が少ないし、バージョンも2018/12/20の時点ではまだ1.0.0rc4
正直、今回くらいの利用ではあまり困ったところもなく、Web APIのテストをやる程度でしたら大分楽に記述出来ました。
Selenium使ってフロントエンド含めたテストをやると大変かもしれませんが、今回そこはスコープ外なので考慮していません。
もう少し本格的にプロダクトチーム内でRobot Frameworkの導入をしてみようと思いますので、また新たな発見などあったら紹介させて頂こうと思います。