KyashのAPIのテストにおけるPostmanの運用方針

Kyash QAチーム*1@konifar です。

Kyashでは、一部のAPIに対してQAチームがテストを実施しています。開発経験のないメンバーもいるため、GUIで比較的簡単に操作できるPostmanを採用しています。

自分はもともとPostmanを単なるcurlの上位互換のようなものとして認識していたのですが、実はかなり高機能で、変数を利用したりフォルダ分けて一斉に実行したり、実行後のレスポンスやステータスコードの検証をJavaScriptのコードで書けたりもします。実行前にスクリプトで任意の処理を実行もできますし、NewmanというCLIツールを使えばCIに組み込むこともできます。便利ですね!

この記事では、KyashのQAチームでPostmanを利用する上での機能の使い分けや命名規則などの運用方針を紹介します。未だ完璧なものではないので、よりよい意見があれば是非教えていただけるとありがたいです。

Collectionsのルール

Collectionsとはリクエストをグルーピングできる機能です。

指針

  • 同時実行する単位でまとめる
  • ネストは最大4つまで。深くしすぎない
  • Pre-request Script、Testsの共通化をしやすい形にする
  • 日本語表記OK。パッと見た時に開発/QAが何を行うのかを理解しやすくするため*2

|-- 単体テスト
|    |-- {メソッド} {エンドポイント} 
|        例) POST /oauth
|        |-- {エンドポイント}_{ステータスコード}_{詳細コード}_{ケース名}
|            例) /oauth_200_success, /oauth_400_invalidclient_clientidが違う

Environmentsのルール

Environmentsは、リクエストのURLやパラメータなどに変数/定数を使うための機能です。

指針

  • サーバーの環境ごとに分ける
  • 環境ごとに先にセットしておく定数は Screaming snake case
  • スクリプト内でセットする一時変数は Lower camel case

  • 環境ごと (Dev / Staging / Prod)
    • BASE_URL : エンドポイントのURL
    • VALID_CLIENT_ID : 有効なclient id
    • VALID_CLIENT_SECRET : 有効なclient secret
  • 一時変数
    • accessToken : OAuthリクエストのレスポンスのtoken
    • uuid : リクエストで使うUUID v4

Pre-request Scriptのルール

Pre-request Scriptは、リクエストの実行前に任意の処理をJavaScriptで実行できる機能です。

指針

  • 通化できるものはCollectionのScriptとして書く
    • PostmanのScriptはファイルやモジュールに切り出して再利用することができないため、重複してメンテナンスしなくて済むようなるべく共通処理として書いています
  • ログは内容がわかる形で多めに出力しておく
    • NewmanでCIで実行する際にデバッグしやすいようにするため

Environmentの取得とBase64 Encode

const clientId = pm.environment.get('VALID_CLIENT_ID');
const clientSecret = pm.environment.get('VALID_CLIENT_SECRET');

// Base64 Encodeして変数に値をセット
const base64encodedAuthorization = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(`${clientId}:${clientSecret}`));
console.log(`base64encodedAuthorization: ${base64encodedAuthorization}`);
pm.environment.set("base64encodedAuthorization", base64encodedAuthorization);

uuidの生成

const uuid = require('uuid').v4();
console.log(`uuid:${uuid}`);
pm.environment.set('uuid', uuid);

リクエスト前のtokenの取得

// access tokenを取得して変数に値をセット
const baseUrl = pm.environment.get('BASE_URL');
pm.sendRequest({
    url: `${baseUrl}/oauth`,
    method: 'POST',
    header: {
        'Authorization': `Basic ${base64encodedAuthorization}`, 
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: {
        mode: 'urlencoded',
        urlencoded: [
            {key: 'grant_type', value: 'xxxxxxxx''},
            {key: 'scope', value: 'xxxxxxxx'}
        ]
    }
}, (err, res) => {
    if (err) {
        console.log(err);
        throw new Error('Error has occurred. Check logs.');
    }
    switch (res.code) {
        case 200: {
            // 成功した場合はtokenを変数にセット
            const token = res.json().token;
            console.log(token);
            pm.environment.set(token, token);
            return;
        }
        default: {
            console.log(res);
            throw new Error(`Error code:${res.code}`);
        }
    }
});

pm.sendRequest() を使ったサンプルは以下のGistにまとまっています。 https://gist.github.com/madebysid/b57985b0649d3407a7aa9de1bd327990

Testsのルール

Testsは、リクエストの結果をJavaScriptで検証できる機能です。Snippetが豊富に用意されており、基本的なテストコードはGUIでポチポチすれば作れます。

指針

ステータスコードの検証

pm.test("ステータスコードが200", function () {
    pm.response.to.have.status(200);
});

レスポンスのjson keyがあることの検証

pm.test("レスポンスにtokenが入っている", function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData).to.have.property('token');
});

レスポンスのjsonの値が空白じゃないことの検証

pm.test("レスポンスにtokenが入っている", function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData.token).not.to.eql('');
});

レスポンスのjsonの値の検証

pm.test("レスポンスのexpires_inが3600", function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData.expires_in).to.eql(3600);
});

レスポンスのjsonの値が今日の日付であることの検証

pm.test("レスポンスにdeleted_atが今日の日付である", function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData).to.have.property('deleted_at');
    const today = require('moment')().format('YYYY-MM-DD');
    pm.expect(jsonData.deleted_at).to.include(today);
});

レスポンスのjsonの値が数字であることの検証

pm.test("レスポンスにamountの値が入っている", function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData).to.have.property('amount');
    pm.expect(jsonData.amount).be.a('number')
});

CIへの組み込み

Kyashでは、ある環境へのデプロイが完了したことをトリガにして特定のCollectionのリクエストを実行するGitHub Actionsワークフローを組んでいます。

Newmanを使った実行方法は、公式のRunning collections on the command line with Newmanを読むとよいです。

GitHub Actionsを使う場合は、newman-actionというものもありますが、実行結果をSlack通知するなどのフローを組みにくかったため使っていません。

GitHub Actionsの定義の例を載せておきます。もっといい書き方があれば教えてもらえるとありがたいです。

name: newman run

on:
  # デプロイのワークフローが完了したら
  workflow_run:
    workflows: ["deploy"]
    branches:
      - xxxxx
    types: 
      - completed

jobs:
  on-success:
    runs-on: ubuntu-latest
    steps:
      - name: Setup node
        uses: actions/setup-node@v1
        with:
          node-version: '14.x'

      - name: Install newman
        run: sudo npm install -g newman

      - name: Download collection and environment settings json
        run: |
          curl -H "X-Api-Key:$POSTMAN_API_KEY" https://api.getpostman.com/collections/$POSTMAN_COLLECTION_ID > collection.json
          curl -H "X-Api-Key:$POSTMAN_API_KEY" https://api.getpostman.com/environments/$POSTMAN_ENVERONMENT_ID > env.json
        env:
          POSTMAN_API_KEY: ${{ secrets.POSTMAN_API_KEY }}
          POSTMAN_COLLECTION_ID: ${{ secrets.POSTMAN_COLLECTION_ID }}
          POSTMAN_ENVERONMENT_ID: ${{ secrets.POSTMAN_ENVERONMENT_ID }}

      - name: Run newman
        run: newman run collection.json --environment=env.json

      - name: Cleanup
        run: |
          rm -f collection.json
          rm -f env.json

今後の方針

ここまでPostmanの運用をどうしているかを書いてきましたが、実はPostmanをやめてコード管理しやすいものに乗り換えることを検討しています。PostmanはGUIでメンテしやすい一方で、Gitなどでバージョン管理しにくいという運用上の課題があるためです。

Postmanの定義をバージョン管理する場合、CollectionやEnvironmentをJSON Exportする必要がありますが、その定義が複雑で差分がわかりにくいという課題があります。GitHubで管理するための仕組みを作るのも面倒です。また、Pre-Request ScriptやTestsは自由度が高く便利ですが、使い回しができずコピペも増えてしまいます。

やり方はまだ確定していませんが、zoncoenさんのscenarigoなどを利用すれば載せ替えのコストも少なく、開発メンバーもQAメンバーも今よりメンテナンスしやすくなりそうです。

Postmanを使ってまずQAチームでAPIのテストが軌道にのるところまでやってきたのはよい判断だったと感じています。今はAPIのテストのフェーズが一段上がったという話で、今後はQAチームのメンバーもGUI以外でテストを書けるようにしていくことで、より適切な分業体制を作っていきたいと考えています。


Kyashでは、エンジニアやデザイナー、プロダクトマネージャーなど色々募集中です。

herp.careers

github.com

カジュアル面談も転職の意思を問わず歓迎しますのでお気軽にお申し込みください。

docs.google.com

*1:QAチーム自体の紹介はKyash QAチームの改善の取り組みについてをご参照ください。

*2:Kyashは2021年9月現在日本語が公用語です。今後変わる可能性はあります。