😺

Postman テストテンプレートとコントラクトテスト

に公開

Postmanは主にAPIツール開発のテスト目的に使われることが多いと思いますが、チーム間でもコラボレーションを促進させるための機能が豊富です。
ワークスペースへ開発者に参加してもらうことで、複数名のペアプロならぬペアテストができます。そしてコレクションにはAPI呼び出し、変数、Pre-Request/Post-Responseによるスクリプト実行のほかにマークダウンエディターが付随しておりAPI諸元や利用目的などを定義しておくことができます。

テストテンプレート

それらをあらかじめサンプルとしてパッキングされたものが、テストテンプレートとして提供されています。
シナリオテスト用テンプレとはこちらからアクセスできます。
https://www.postman.com/templates/collections/api-scenario-testing/
画面下部のUse Templateボタンをクリックすると自分のワークスペースにシナリオテスト用テンプレートが作成されます。
https://web.postman.co/redirect/workspace?collectionTemplateId=78475d97-9a36-4731-ab24-9adf6a94d0fb


echoを呼び出してすぐ送信ボタンを押すことが可能です。ここから自分の環境用にAPI情報、変数、パラメータ、ヘッダ、ボディ、Pre-Request/Post-Response、API諸元のマークダウンなどを書き換えていくことで、一から作るより素早くシナリオテスト環境を作成することが可能です。逆に言えば、このテンプレートを使わなくても慣れている人であれば同じシナリオテスト環境は作れますが、なにか土台があると作業がはかどるものです。

コントラクトテスト

コントラクトテストとは、APIで連結させる二つのシステムの通信が正しく行われることを検証するテスト手法です。クライアント(Consumer) と プロバイダ(Provider) 間でやりとりするデータの契約(Contract)を定義し、それに基づいてテストを実施します。
ここでいう契約(Contract)とはやり取りを行うパラメータの型や値のチェック(バリデーション)を指します。
結合テストを行う前に局地的にコントラクトテストを行うことで、結合テスト時に発生する問題を減らす効果が期待できます。

Postmanが提供しているテンプレートは以下にあります。
https://www.postman.com/templates/collections/contract-testing/
https://go.postman.co/redirect/workspace?collectionTemplateId=42247877-8529-429d-acba-4de20c3b5b3b

それぞれのAPI呼び出しごとにやり取りを行うパラメータの型や値のバリデーション用スクリプトが挿入されています。

スクリプトはこちらの記事で触れていますが、単純なJavaScriptです。https://zenn.dev/kameoncloud/articles/1cfc13d988aeaf
pmというオブジェクトはPostman専用オブジェクトとして定義されますが、サンプルは以下です。

// Validate that the response code should be 200
pm.test("Status code is 200", function () {
    pm.response.to.have.status(200);
});

// Validate that the response is json object
pm.test("Response is a json object", function () {
    pm.expect(pm.response.json()).to.be.an('object');
});

// Validate that the response has an arg object
pm.test("Response to have 'arg' object", function () {
    pm.expect(pm.response.json()).to.have.property('args');
});

// Validate that the response has headers object
pm.test("Response to have 'headers' object", function () {
    pm.expect(pm.response.json()).to.have.property('headers');
});

// Validate that the response has url property
pm.test("Response to have 'url' property", function () {
    pm.expect(pm.response.json()).to.have.property('url');
});

個別のAPIコールを実行して呼び出すことも可能ですし、上位のコレクションからまとめて実行することで、コレクションの下に格納されている複数のAPI呼び出しをまとめて実行させることもできます。

過去負荷テストの記事でも紹介しましたが、呼び出し時間間隔を秒単位で指定して連続呼び出しを行うことも可能です。
https://zenn.dev/kameoncloud/articles/c3b6f6a2ac3445

呼び出しの成功/失敗の他にこのように値のバリデーション結果なんかも取得できます。

OpenAPI や Swagger

コントラクトテストの様なAPIの型定義を重視したテストの場合、APIの定義ファイルが別に存在するケースがあります。代表的なものとしてOpenAPIやSwaggerなどのAPI定義フォーマットファイルがあります。

{
  "openapi": "3.0.0",
  "info": {
    "title": "Sample API",
    "description": "OpenAPI 3.0 (Swagger UI対応) のサンプル",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.example.com",
      "description": "Example API Server"
    }
  ],
  "paths": {
    "/users": {
      "get": {
        "summary": "ユーザー一覧を取得",
        "description": "全ユーザーのリストを返す",
        "responses": {
          "200": {
            "description": "成功時のレスポンス",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "id": { "type": "integer" },
                      "name": { "type": "string" }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "新しいユーザーを作成",
        "description": "ユーザー情報を登録する",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": { "type": "string" }
                },
                "required": ["name"]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "ユーザーが作成された",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "integer" },
                    "name": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/users/{id}": {
      "get": {
        "summary": "特定のユーザーを取得",
        "description": "IDで指定されたユーザー情報を返す",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "integer" }
          }
        ],
        "responses": {
          "200": {
            "description": "成功時のレスポンス",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": { "type": "integer" },
                    "name": { "type": "string" }
                  }
                }
              }
            }
          },
          "404": {
            "description": "ユーザーが見つからない"
          }
        }
      }
    }
  }
}

これらをインポートしてコレクションを作成することも可能です。ただしPre-requestやPost-scriptはPostman独自機能ですのでサンプルテンプレートをもとに作っていくことになります。

Discussion