要約
手動でリクエストを実行する際に設定された変数は、PostmanのCollection Runnerで同じコレクションを実行すると、しばしば消えてしまいます。根本的な原因は変数のスコープの不一致です。pm.environment.setは、Runnerでは手動モードとは異なる動作をし、コレクション変数は環境変数とは異なる動作をします。このガイドでは、なぜこのようなことが起こるのか、そしてどのように解決するのかを正確に説明し、Apidogが誤って設定しにくい方法で変数スコープをどのように処理するかを示します。
はじめに
PostmanでAPIを手動でテストしていました。ログインリクエストを実行し、プリリクエストスクリプトが認証トークンを設定し、後続のリクエストはそれを問題なく取得します。すべてが機能します。
そして、「コレクションを実行」をクリックします。Runnerが起動し、ログインリクエストは成功しますが、次のリクエストは401で失敗します。トークンがありません。
このシナリオは、Stack OverflowやPostmanコミュニティフォーラムで繰り返し現れます。回答は通常、変数スコープを指摘しますが、手動テストとRunnerの間で動作が異なる理由を完全に説明することはめったにありません。
これを理解するには、Postmanの変数スコープ階層を理解する必要があります。それが明確になれば、解決策は簡単です。
Postmanの変数スコープ階層
Postmanには5つの変数スコープがあり、優先度の高い順から低い順にリストされています。
- ローカル変数 – 現在のスクリプト実行内でのみ利用可能で、リクエストをまたいでアクセスすることはできません。
- データ変数 – データ駆動型実行のためにCSVまたはJSONファイルからロードされます。
- コレクション変数 – コレクションにスコープされ、そのコレクション内のリクエストをまたいで持続します。
- 環境変数 – 選択された環境にスコープされ、コレクションをまたいで持続します。
- グローバル変数 – どの環境のどのコレクションでも利用可能です。
Postmanが{{token}}のような変数参照を解決するとき、このリストをたどり、最初に見つかったものを使用します。
問題は、「持続する」がコレクションの実行方法によって異なる意味を持つことです。
Collection Runnerで変数が消える理由
「現在の値」と「初期値」の違い
Postmanのすべての変数には、「初期値」と「現在の値」の2つのフィールドがあります。
- 初期値はPostmanのクラウドと同期され、チームメイトと共有されます。
- 現在の値はあなたのマシンにローカルであり、同期されることはありません。
pm.environment.set('token', value)を使用してスクリプトで変数をプログラム的に設定すると、Postmanはアクティブな環境の現在の値を更新します。
手動テストモードでは、ローカルの現在の値が同じセッション内の個々のリクエスト実行をまたいで持続するため、これは期待どおりに機能します。
Collection Runnerでは、動作が変わります。Runnerは、実行開始時の環境の現在の状態から各実行を開始します。実行中に変数を更新するスクリプトは、その実行内では正しく機能します。しかし、Runnerが実行間に変数をクリアするように構成されている場合、または初期値が空でRunnerが新しい環境スナップショットを使用する場合、スクリプトが実行されても変数が持続しないように見える状態になる可能性があります。
環境変数とコレクション変数の問題
ここがより一般的な罠です。応答後スクリプトで変数を設定しています。
pm.environment.set('token', pm.response.json().access_token);
これはアクティブな環境に変数を設定します。しかし、Collection Runnerには「変数の値を保持する」というオプションがあります。このチェックボックスがオフの場合(デフォルトはオフ)、Runnerは実行後に環境変数を初期値にリセットします。実行中に設定された値はすべて破棄されます。
環境が選択されていない状態でコレクションを実行している場合、pm.environment.setはサイレントに失敗します。書き込む環境がありません。変数は消えます。
手動モードとRunnerモード間のスコープの不一致
手動テストでは、通常、環境が選択されており、Postmanセッション全体で持続します。リクエストを実行し、変数を設定し、別のリクエストを実行すると、それらはすべて同じ持続的な環境コンテキストで発生します。
Collection Runnerは、別の実行コンテキストを作成します。開始時に環境の状態をロードし、すべてのリクエストを実行し、その後(「変数の値を保持する」にチェックがない限り)、環境を実行前の状態に戻します。
これは、Runnerで1つのリクエストによって設定された変数が、同じ実行内の後続のリクエストで利用可能になることを意味しますが、明示的に保持しない限り、実行終了後に環境パネルに持続することはありません。
修正
修正1:Runnerで「変数の値を保持する」にチェックを入れる
Collection Runnerで、実行をクリックする前に:
- Runner設定パネルで「変数の値を保持する」オプションを探します。
- このボックスにチェックを入れます。
これにより、実行が完了した後、Runnerは変数への変更をアクティブな環境に書き戻すようになります。実行中にスクリプトによって設定された変数は、実行終了時に環境パネルに表示されます。
これを使用する場合:Runnerが共有状態を更新することを望む場合、たとえば他のツールや後続の実行が使用する認証トークンを更新する場合など。
これを使用しない場合:複数のイテレーションを実行しており、イテレーション1で設定された変数がイテレーション2を汚染する場合。その場合は、データファイルを使用するか、各イテレーションの開始時に変数を明示的にリセットします。
修正2:実行内の状態には環境変数の代わりにコレクション変数を使用する
変数が同じコレクション実行内のリクエスト間で共有される必要があるだけの場合は、環境変数の代わりにコレクション変数を使用します。
// ログインリクエストの応答後スクリプトで:
pm.collectionVariables.set('token', pm.response.json().access_token);
// 後続のリクエストのプリリクエストスクリプトで:
const token = pm.collectionVariables.get('token');
コレクション変数は、環境が選択されているかどうかに関係なく、Runnerで常に利用可能です。これらはコレクション実行の期間中持続します。これらは、単一のコレクション内で設定および消費される値に適したスコープです。
修正3:実行前に環境が選択されていることを確認する
アクティブな環境がない場合、pm.environment.setはサイレントに失敗します。コレクションを実行する前に:
- Collection Runnerを開きます。
- 「環境」ドロップダウンで環境が選択されていることを確認します。
- 環境レベルの変数が必要ない場合は、代わりにコレクション変数を使用します(修正2)。
修正4:常に存在するべき変数には初期値を使用する
baseUrlのような変数が実行の最初のリクエストから利用可能である必要がある場合は、環境の初期値として設定し、現在の値だけでなく設定します。
環境エディタで:
- 「現在の値」フィールドだけでなく、「初期値」フィールドを設定します。
- 初期値は、Runnerが開始状態として使用するものです。
現在の値のみが設定されており、Runnerがローカルの現在の値にアクセスできない場合(たとえば、チームメイトがコレクションを実行している場合、またはNewman/Apidog CLI実行の場合)、変数は空で開始されます。
修正5:コンソールロギングでデバッグする
プリリクエストスクリプトと応答後スクリプトにconsole.logを追加して、何が起こっているかを正確に確認します。
// プリリクエストスクリプト
console.log('token before request:', pm.collectionVariables.get('token'));
console.log('environment token:', pm.environment.get('token'));
コレクションを実行する前にPostmanコンソール(表示 > Postmanコンソールを表示)を開きます。ログは、各変数がどのスコープから読み取られ、各ステップでどのような値を持っているかを正確に示します。
Apidogが変数スコープを処理する方法
Apidogは、グローバル、環境、コレクション、ローカルという同じスコープ階層を使用します。主な違いはUIにあります。
Apidogの変数エディタでは、初期値と現在の値が明示的なラベルと色で表示されます。このインターフェースにより、誤って現在の値のみを設定してしまうことが難しくなります。スクリプトがpm.environment.setを使用して変数を設定すると(Postman互換のためにApidogがサポートしている機能)、環境パネルは視覚的にリアルタイムで更新され、変更が起こるのを確認できます。
また、ApidogのテストRunnerは、明示的に設定しない限り、ステップ間で変数の値をリセットしません。デフォルトの動作は、実行内のリクエスト間で変数の状態を保持することであり、これはほとんどの開発者が手動テストに期待することと一致します。
チームのシナリオでは、Apidogのローカルファーストモデルは、環境変数がディスクに保存されることを意味します。実行間で現在の値を上書きするクラウド同期はありません。
よくある間違いの要約
| 間違い | 症状 | 修正 |
|---|---|---|
| 環境が選択されていない | pm.environment.setがサイレントに失敗する |
環境を選択するか、コレクション変数を使用する |
| 現在の値のみが設定されている | CIまたはチームメイトのマシンで変数が欠落している | 環境エディタで初期値を設定する |
| 変数の値を保持するのチェックが外れている | Runner完了後に変数がリセットされる | Runner設定で「変数の値を保持する」にチェックを入れる |
| 実行内の状態に環境変数を使用している | 手動モードでは機能するが、Runnerでは失敗する | pm.collectionVariables.setに切り替える |
| ログで誤ったスコープを確認している | 変数は存在するが、誤った値が使用されている | 両方のスコープをログに記録し、解決の優先順位を確認する |
FAQ
pm.environment.setが手動モードでは機能するのに、Runnerでは機能しないのはなぜですか?手動モードでは、持続的な環境セッションがあります。Runnerでは、環境は実行の開始時にロードされ、デフォルトでは終了時にリセットされます。実行中に変数を設定するスクリプトは、その実行内の後続のリクエストでは引き続き機能しますが、「変数の値を保持する」にチェックがなければ、変更は環境に持続しません。
pm.environment.setとpm.collectionVariables.setの違いは何ですか?pm.environment.setは、その環境を使用するすべてのコレクションで共有されるアクティブな環境に書き込みます。pm.collectionVariables.setは、特定のコレクションに紐付けられたスコープに書き込みます。1つのコレクション実行内でしか意味のない値の場合、コレクション変数の方が適切であり、環境を選択する必要がありません。
この問題はNewmanでも発生しますか?はい。Newmanも同じスコープモデルを持っています。デフォルトでは、Newmanはエクスポートされた環境の初期値で各実行を開始し、--export-environmentフラグを使用して最終的な環境状態をファイルに書き込まない限り、実行後に変更を永続化しません。
Newmanの--export-environmentフラグとは何ですか?これは、Newmanに、実行中にスクリプトによって設定された値を含む環境の最終状態を、実行完了後にJSONファイルに書き込むように指示します。その後、そのファイルを次の実行の環境として渡すことができます。これは、1つの実行が次の実行で使用されるトークンを生成するパイプラインで役立ちます。
Apidogはpm.collectionVariables.setをサポートしていますか?はい。Apidogは、pm.collectionVariables.set、pm.collectionVariables.get、pm.environment.set、pm.environment.getを含むPostmanスクリプトAPIの全機能をサポートしています。Postmanから移行されたコレクションは同じスクリプト構文を使用します。
Postmanでコレクション間で変数を渡すにはどうすればよいですか?グローバル変数を使用します:pm.globals.set('token', value)。グローバル変数は、Postmanセッションの存続期間中、コレクションや環境をまたいで持続します。グローバル変数はスコープされず、名前の衝突を引き起こす可能性があるため、チーム設定でこのアプローチを使用する場合は注意が必要です。
Postmanにおける変数スコープの問題は、APIテストスイートにおける偽陰性の最も信頼できる原因の1つです。手動では合格するがRunnerでは失敗するテストは、信頼できるテストではありません。スコープモデルを理解し、適切なコンテキストで適切なセッターを使用し、必要に応じて「変数の値を保持する」にチェックを入れることが、これらの問題のほとんどを解決する3つの方法です。
