PostmanのCollectionをCircleCIで定期的に実行してみた

APIを継続的に開発/デプロイをしていると、単体テストでは全て正常なのに複数のAPIを特定のシナリオで実行したときに異常が起きるケースがありますよね。これを自動で検知するために、PostmanのCLI runnerであるnewmanとCircleCIで定期的にAPIのシナリオテストを自動で行う仕組みを作ってみました。

TL;DR

  • PostmanのCollectionはnewmanというCLIのrunnerで実行できるよ
  • CircleCIの2.1でサポートされたOrbsとSchedule機能が便利だよ
  • 同じことをPostmanのMonitorsからもできるけどnewmanの方が便利な場合もあるよ

環境

  • MacOS: 10.14.5
  • Node: v10.15.3

PostmanのCollectionを作成する

まずはPostmanでCollection(テストケースの集まり)を作ります。

この記事ではサンプルとして Postman Echo のCollectionを利用させてもらいます。

  1. ページ右上の Run in Postman ボタンから、PostmanのクライアントアプリにCollectionをインポートします。クライアントアプリがインストールされていない場合は、先にインストールをします。
  2. Postmanのクライアントアプリで、インポートしたCollectionを Run で実行して、テストが実行されることを確認します。テストが全部成功しなくても手順の確認としては問題ありません。
  3. Postmanのクライアントアプリで、インポートしたCollectionを Export します。ファイル名を collection.json とします。

newmanでCollectionを実行する

  1. newmanを npm install -g newman でインストールします。
  2. newman run ./collection.json でテストが実行されることを確認します。

CircleCIでnewmanを使ってCollectionを実行する

CircleCIでnewmanを使う方法は、この記事に詳しく書いてあります。

Set up a CircleCI pipeline to run a Postman collection using the Newman orb

この記事ではCircleCI 2.1から導入されたOrbsという「ある特定の処理を実行するための環境やコマンドがまとめられたパッケージのようなもの」を使っています。PostmanがCircleCIでnewmanを実行するために公式で提供しているOrbがこちらです。

postman/newman

OrbはCircleCI 2.1から導入された機能なので、configも2.1の記法に従う必要があります。まだキャッチアップされてない場合は、こちらの記事を読むと良いです。

CircleCI 2.1 Config Overview

あと、Orbsを使うために、CircleCIの設定を2点変更する必要があります。

  1. リポジトリの設定の Settings >> Advanced Settings にて、Enable pipelinesをOnにします。
  2. 全体の設定の Settings >> security にて、3rd PartyのOrbの使用を許可します。

それではサンプルプロジェクトを作成してCircleCIでCollectionを実行してみましょう。

プロジェクト構成

.
├── .circleci
│   └── config.yml
└── postman
    └── collection.json

.circleci/config.yml

version: 2.1
orbs:
  newman: postman/newman@0.0.2
workflows:
  commit:
    jobs:
      - newman-collection-run
jobs:
  newman-collection-run:
    executor: newman/postman-newman-docker
    steps:
      - checkout
      - newman/newman-run:
          collection: ./postman/collection.json

GitHubにCommitをPushして、CircleCIのジョブが実行されました。

#!/bin/sh -eo pipefail
newman run ./postman/collection.json               
newman

Postman Echo

❏ Request Methods
↳ GET Request
  GET https://postman-echo.com/get?foo1=bar1&foo2=bar2 [200 OK, 629B, 115ms]
  ✓  response is ok
  ✓  response body has json with request queries

↳ POST Raw Text
  POST https://postman-echo.com/post [200 OK, 658B, 7ms]
  ✓  response is ok
  ✓  response body has json with request body

(中略)

┌─────────────────────────┬──────────────────┬─────────────────┐
│                         │         executed │          failed │
├─────────────────────────┼──────────────────┼─────────────────┤
│              iterations │                1 │               0 │
├─────────────────────────┼──────────────────┼─────────────────┤
│                requests │               37 │               0 │
├─────────────────────────┼──────────────────┼─────────────────┤
│            test-scripts │               37 │               0 │
├─────────────────────────┼──────────────────┼─────────────────┤
│      prerequest-scripts │                0 │               0 │
├─────────────────────────┼──────────────────┼─────────────────┤
│              assertions │               90 │               9 │
├─────────────────────────┴──────────────────┴─────────────────┤
│ total run duration: 4.3s                                     │
├──────────────────────────────────────────────────────────────┤
│ total data received: 12.58KB (approx)                        │
├──────────────────────────────────────────────────────────────┤
│ average response time: 98ms [min: 4ms, max: 2s, s.d.: 325ms] │
└──────────────────────────────────────────────────────────────┘

  #  failure         detail                                                                                                     

 1.  AssertionError  response body has json saying passed 'status'                                                              
                     expected { Object (message) } in response to contain property 'status'                                     
                     at assertion:1 in test-script                                                                              
                     inside "Authentication Methods / Hawk Auth"                                                                

 2.  AssertionError  response has chunked transfer encoding header                                                              
                     expected response to have header with key 'transfer-encoding'                                              
                     at assertion:1 in test-script                                                                              
                     inside "Utilities / Streamed Response"                                                                     

(中略)

Exited with code 1

失敗したテストケースがあると終了コードが1になるので、CircleCIのジョブも失敗します。

GraphQLの場合

ここまでの内容は一般的なAPIでしたが、私がやりたかったのはGraphQLのテストでした。実はPostmanは最近のアップデートでGraphQLに正式に対応しました。(いままでもリクエストのBodyを頑張って書けばできたけど、頑張らなくて良くなりました。)

Postman v7.2 Supports GraphQL

私はこれを使っており、これで作ったCollectionをOrbの postman/newman@0.0.2 で実行してみたのですが、newmanのバージョンが古いためか正しく動きませんでした。なのでOrbは使わず、普通にnpmで最新のnewmanをインストールして実行するように、以下のようにconfigを修正しました。

version: 2.1
# orbs:
#   newman: postman/newman@0.0.2
executors:
  node10-executor:
    docker:
      - image: circleci/node:10.10-stretch
workflows:
  commit:
    jobs:
      - newman-collection-run
jobs:
  newman-collection-run:
    # executor: newman/postman-newman-docker
    # steps:
    #   - checkout
    #   - newman/newman-run:
    #       collection: ./postman/collection.json
    executor: node10-executor
    steps:
      - checkout
      - run: sudo npm install -g newman
      - run: newman run ./postman/collection.json

CircleCIのジョブを定期的に実行する

あとはこのジョブを定期的に実行するようにします。これもCircleCI 2.1からの機能で、コミットしなくてもスケジューラによりジョブを起動できるようになりました。

例えば、ジョブを毎日00:00(JST)に実行させたい場合は、configを以下のように修正します。

workflows:
  # commit:
  #   jobs:
  #     - newman-collection-run
  nightly:
    jobs:
      - newman-collection-run
    triggers:
      - schedule:
          cron: "00 15 * * *" # UTC
          filters:
            branches:
              only:
                - master

Appendix: Postman(web)でCollectionを定期的に実行する

ところで、一通りの検証が終わってから気づいたのですが、PostmanのWebコンソールを使うとMonitorという機能でCollectionを定期的に実行することができるんですね。フリープランだと回数制限が少なかったり通知の手段がメールだけだったりと制約はあるものの、用途によってはこちらで十分な場合もあるかと思います。

ちなみにGraphQLのCollectionも現時点(2019/07/04)では対応していませんでしたが、直に対応するでしょう。

おわりに

今回の検証で改めてPostmanを色々調べてみてまだ使ってない便利機能がありそうなので、有料プランも視野にプロジェクトでの活用を検討したいと思いました。あとCircleCIの2.1はかなり良いアップデートなので全部のリポジトリのconfigをバージョンアップしたいと思いました。