本記事は、Postman Script examples の日本語訳です(2024年5月13日更新)。
この記事では、Postman の様々な API テストシナリオのための Post-response スクリプトの例を説明します。これらの Post-response スクリプトをリクエストで使用すると、レスポンスデータをパースしてアサーションを行うことができます。また、これらのスクリプトを使ってレスポンスの構造を検証したり、よくあるテストエラーのトラブルシューティングを行ったりすることもできます。
初めて Post-response スクリプトを作成するときは、まず Postman でリクエストを開き、Scripts > Post-response タブを選択します。そして、次の JavaScript コードを入力してください:
pm.test("ステータスコードは 200", function () {
pm.response.to.have.status(200);
});
このコードでは、pm
ライブラリを使って test
メソッドを実行しています。テキスト文字列はテストの出力に現れます。テスト内の関数はアサーションを表します。Postman のテストでは Chai Assertion Library BDD 構文を使うことができ、これはテストの可読性を高めることに役立ちます。この場合、コードは BDD 形式の to.have
チェーンを使用してアサーションを表現します。
このテストは API が返すレスポンスコードをチェックします。レスポンスコードが 200
ならテストは合格、そうでなければ失敗です。送信を選択し、レスポンスエリアのテスト結果タブに移動してください。
テスト結果が合格あるいは失敗の場合にどのように見えるかを確認するには、アサーションコード内のステータスコードを変更して、リクエストをもう一度送信してみましょう。
結果をどのように出力したいかによって、さまざまな方法でテストアサーションを構成できます。次のコードは、上のコードと同じテストを expect
構文で行うものです:
pm.test("ステータスコードは 200", () => {
pm.expect(pm.response.code).to.eql(200);
});
アサーション構文オプションの完全な概要については、Chai Assertion Library Docs を参照してください。
複数のアサーションを使用する
ひとつのテストに複数のアサーションを含めることができます。これを使用して、関連するアサーションをひとまとめにします:
pm.test("レスポンスはすべてのプロパティを持つ", () => {
// レスポンス JSON をパースして、3つのプロパティをテストする
const responseJson = pm.response.json();
pm.expect(responseJson.type).to.eql('vip');
pm.expect(responseJson.name).to.be.a('string');
pm.expect(responseJson.id).to.have.lengthOf(1);
});
含まれるアサーションのいずれかが失敗すると、テスト全体が失敗となります。テストに合格するには、すべてのアサーションが成功しなければなりません。
レスポンスボディデータをパースする
レスポンスに対してアサーションを実行するには、まずデータをパースしてアサーションが使用できる JavaScript オブジェクトにする必要があります。
JSON データをパースするには、次の構文を使用します:
const responseJson = pm.response.json();
XML をパースするには、以下を使用します:
const responseJson = xml2Json(pm.response.text());
複雑な XML レスポンスを扱っている場合、コンソールログ出力が役に立つかもしれません。
CSV をパースするには、CSV parse (csv-parse/lib/sync) ユーティリティを使用します:
const parse = require('csv-parse/lib/sync');
const responseJson = parse(pm.response.text());
HTML をパースするには cheerio を使用します:
const $ = cheerio.load(pm.response.text());
// html をテスト用に出力
console.log($.html());
パースできないレスポンスを処理する
レスポンスボディが JSON、XML、HTML、CSV などのパース可能なデータ形式でフォーマットされていないために JavaScript でパースできない場合でも、データに対してアサーションを行うことができます。
レスポンスボディに特定の文字列が含まれているかどうかをテストします:
pm.test("ボディは文字列を含む",() => {
pm.expect(pm.response.text()).to.include("customer_id");
});
上の例は、レスポンスボディ全体に対してテストを実行するため、文字列がどこで検出されたかはわかりません。レスポンスが文字列に一致するかどうかは、次のようにテストします:
pm.test("ボディは文字列", function () {
pm.response.to.have.body("whole-body-text");
});
HTTP レスポンスに対するアサーションを作成する
ボディ、ステータスコード、ヘッダー、Cookie、レスポンス時間など、 リクエストレスポンスのさまざまな側面をチェックすることができます。
レスポンスボディをテストする
レスポンスボディ内の特定の値をチェックします:
/* レスポンスは以下のような構造を持つ:
{
"name": "一郎",
"age": 23
},
*/
pm.test("人物は一郎", () => {
const responseJson = pm.response.json();
pm.expect(responseJson.name).to.eql("一郎");
pm.expect(responseJson.age).to.eql(23);
});
ステータスコードをテストする
レスポンスのステータスコードをテストします:
pm.test("ステータスコードは 201", () => {
pm.response.to.have.status(201);
});
ステータスコードが集合のひとつであることをテストしたい場合は、それらをすべて配列に含めて oneOf
を使用します:
pm.test("POST リクエストに成功", () => {
pm.expect(pm.response.code).to.be.oneOf([201,202]);
});
ステータスコードのテキストをチェックします:
pm.test("ステータスコード名は文字列", () => {
pm.response.to.have.status("Created");
});
ヘッダーをテストする
レスポンスヘッダーが存在するかチェックします:
pm.test("Content-Type ヘッダーが存在する", () => {
pm.response.to.have.header("Content-Type");
});
レスポンスヘッダーが特定の値を持つかテストします:
pm.test("Content-Type ヘッダーは application/json", () => {
pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');
});
Cookie をテストする
レスポンスに Cookie が存在するかどうかをテストします:
pm.test("Cookie isLoggedIn が存在する", () => {
pm.expect(pm.cookies.has('isLoggedIn')).to.be.true;
});
特定の Cookie の値をテストします:
pm.test("Cookie isLoggedIn の値は 1", () => {
pm.expect(pm.cookies.get('isLoggedIn')).to.eql('1');
});
レスポンス時間をテストする
レスポンス時間が指定された範囲内であることをテストします:
pm.test("レスポンス時間は 200ms 未満", () => {
pm.expect(pm.response.responseTime).to.be.below(200);
});
一般的なアサーションの例
以下の一般的なアサーションの例は、Post-response スクリプトを記述する際に役立ちます。
アサーションに含めることができる内容のより包括的な概要については、Chai Assertion Library Docs を参照してください。
レスポンス値を変数に対してアサートする
レスポンスのプロパティが変数と同じ値かどうかをチェックします (この例では環境変数を使用):
pm.test("レスポンスプロパティは環境変数と一致する", function () {
pm.expect(pm.response.json().name).to.eql(pm.environment.get("name"));
});
Post-response スクリプトで変数を使用する方法については Using variables を参照してください。
値の型をアサートする
レスポンスの任意の部分の型をテストします:
/* レスポンスは以下のような構造を持つ:
{
"name": "一郎",
"age": 29,
"hobbies": [
"スケート",
"絵画"
],
"email": null
},
*/
const jsonData = pm.response.json();
pm.test("レスポンスのデータ型をテストする", () => {
pm.expect(jsonData).to.be.an("object");
pm.expect(jsonData.name).to.be.a("string");
pm.expect(jsonData.age).to.be.a("number");
pm.expect(jsonData.hobbies).to.be.an("array");
pm.expect(jsonData.website).to.be.undefined;
pm.expect(jsonData.email).to.be.null;
});
配列プロパティをアサートする
配列が空かどうか、また特定の項目が含まれているかどうかをチェックします:
/* レスポンスは以下のような構造を持つ:
{
"errors": [],
"areas": [ "goods", "services" ],
"settings": [
{
"type": "notification",
"detail": [ "email", "sms" ]
},
{
"type": "visual",
"detail": [ "light", "large" ]
}
]
},
*/
const jsonData = pm.response.json();
pm.test("配列のプロパティをテストする", () => {
// errors 配列が空
pm.expect(jsonData.errors).to.be.empty;
// areas 配列には「goods」が含まれる
pm.expect(jsonData.areas).to.include("goods");
// notification settings オブジェクトを取得する
const notificationSettings = jsonData.settings.find
(m => m.type === "notification");
pm.expect(notificationSettings)
.to.be.an("object", "setting が見つからない");
// detail 配列は「sms」を含む
pm.expect(notificationSettings.detail).to.include("sms");
// detail 配列はリストされたすべての項目を含む
pm.expect(notificationSettings.detail)
.to.have.members(["email", "sms"]);
});
.members
の順番はテストに影響しません。
オブジェクトプロパティをアサートする
オブジェクトにキーやプロパティが含まれていることをアサートします:
/* レスポンスは以下のような構造を持つ:
{
"a": 1,
"b": 2
},
*/
pm.expect({a: 1, b: 2}).to.have.all.keys('a', 'b');
pm.expect({a: 1, b: 2}).to.have.any.keys('a', 'b');
pm.expect({a: 1, b: 2}).to.not.have.any.keys('c', 'd');
pm.expect({a: 1}).to.have.property('a');
pm.expect({a: 1, b: 2}).to.be.a('object')
.that.has.all.keys('a', 'b');
ターゲットには、object
、set
、array
、map
を指定できます。.all
または .any
を指定せずに .keys
を実行すると、式のデフォルトは .all
になります。.keys
の動作はターゲットの型によって異なるため、.a
と共に .keys
を使用する前に型を確認することをお勧めします。
値がセット内にあることをアサートする
レスポンス値を有効なオプションのリストと照合します:
/* レスポンスは以下のような構造を持つ:
{
"type": "Subscriber"
},
*/
pm.test("値が有効なリスト内にある", () => {
pm.expect(pm.response.json().type)
.to.be.oneOf(["Subscriber", "Customer", "User"]);
});
オブジェクトが含まれていることをアサートする
オブジェクトが親オブジェクトの一部であることをチェックします:
/* レスポンスは以下のような構造を持つ:
{
"id": "d8893057-3e91-4cdd-a36f-a0af460b6373",
"created": true,
"errors": []
},
*/
pm.test("オブジェクトが含まれている", () => {
const expectedObject = {
"created": true,
"errors": []
};
pm.expect(pm.response.json()).to.deep.include(expectedObject);
});
.deep
を使用すると、チェーン内で後続するすべての .equal
、.include
、.members
、.keys
、.property
アサーションで、厳密な(===
)等価性ではなく深い等価性(緩やかな等価性)が使用されるようになります。.eql
でも緩やかな比較が行われますが、.deep.equal
を使用すると、チェーン内で後続する他のアサーションでも深い等価性の比較が行われるようになります(.eql
では行われない)。
現在の環境をアサートする
Postman のアクティブな環境をチェックします:
pm.test("アクティブな環境をチェックする", () => {
pm.expect(pm.environment.name).to.eql("Production");
});
よくあるテストエラーをトラブルシュートする
Post-response のスクリプトでエラーや予期せぬ挙動に遭遇した場合、Postman コンソールが原因の特定に役立ちます。console.log()
、console.info()
、console.warn()
、console.error()
のデバッグ文とテストアサーションを組み合わせることで、HTTP リクエストやレスポンスの内容、そして変数などの Postman のデータ項目を調べることができます。console.clear()
メソッドを使用して、コンソールから情報を消去することもできます。Postman のフッターからコンソールを選択して開きます。
変数やレスポンスプロパティの値をログに出力します:
console.log(pm.collectionVariables.get("name"));
console.log(pm.response.json().name);
変数やレスポンスプロパティの型をログに出力します:
console.log(typeof pm.response.json().id);
コンソールのログを使用して、コードの実行を記録します。「トレースステートメント」と呼ばれることもあります:
if (pm.response.json().id) {
console.log("id を発見!");
// 何かする
} else {
console.log("id なし...");
// 何か他のことをする
}
深い等価性アサーションエラー
AssertionError: expected <value> to deep equal '<value>'
というエラーが発生することがあります。例えば、次のようなコードで発生します:
pm.expect(1).to.eql("1");
これは、テストが数値と文字列値を比較しているために起こります。このテストは、型と値の両方が等しい場合にのみ真を返します。
変数未定義エラー
ReferenceError: <variable> is not defined
というエラーに遭遇するかもしれません。これは通常、宣言されていない変数を参照しようとしたときや、テストコードのスコープ外の変数を参照しようとしたときに発生します。
次の例では、JSON オブジェクトが最初のテストの変数の値です。二番目のテストはこの変数を参照しようとしていますが、変数が二番目のテストのコードのスコープ外にあるため、参照できません。
/* レスポンスは以下のような構造を持つ:
{
"name": "一郎",
"age": 29
},
*/
pm.test("テスト 1", () => {
const jsonData = pm.response.json();
pm.expect(jsonData.name).to.eql("一郎");
});
pm.test("テスト 2", () => {
pm.expect(jsonData.age).to.eql(29); // ReferenceError: jsonData is not defined
});
テスト関数が変数を参照する必要がある場合は、グローバルスコープで変数を利用できるようにします。先ほどの例では、最初の pm.test
の前に const jsonData = pm.response.json();
を移動させれば、両方のテスト関数で利用できるようになります。
アサーション未定義エラー
AssertionError: expected undefined to deeply equal <value>
というエラーに遭遇するかもしれません。これは通常、存在しないプロパティやスコープ外のプロパティを参照しているときに発生します。
const jsonData = pm.response.json();
pm.expect(jsonData.name).to.eql("一郎");
この例で、AssertionError: expected undefined to deeply equal '一郎'
というエラーが出た場合、これは name
プロパティが jsonData
オブジェクトで定義されていないことを示しています。
テストが失敗しない
テストが失敗すると思っていたのに、失敗しないことがあるかもしれません。テストコードが構文的に正しいことを確認してから、リクエストをもう一度送信してください。
次の例では、true
が false
と等しくないのでテストは失敗すると予想されます。実際にテストが合格するのは、pm.test
関数が正しく定義されていないからです。pm.test
関数には、テスト結果出力に表示されるテキスト文字列である最初のパラメータがありません。pm.test
関数を使ったテストの定義についてはこちらを参照してください。
pm.test( function () {
pm.expect(true).to.eql(false);
});
レスポンス構造を検証する
JSON Schema は、Tiny Validator V4 (tv4) で検証できます:
const schema = {
"items": {
"type": "boolean"
}
};
const data1 = [true, false];
const data2 = [true, 123];
pm.test('スキーマは有効', function() {
pm.expect(tv4.validate(data1, schema)).to.be.true;
pm.expect(tv4.validate(data2, schema)).to.be.true;
});
また、Ajv JSON Schema バリデーターを使用して、JSON Schema でレスポンスデータを検証することもできます:
const schema = {
"properties": {
"alpha": {
"type": "boolean"
}
}
};
pm.test('レスポンスは有効', function() {
pm.response.to.have.jsonSchema(schema);
});
Ajv JSON Schema バリデーターを使ってレスポンスデータを JSON Schema で検証する方法についての詳細はこちらをご覧ください。
非同期リクエストを送信する
テストコードからリクエストを送信し、レスポンスをログに出力することができます:
pm.sendRequest("https://postman-echo.com/get", function (err, response) {
console.log(response.json());
});