Node.jsのテストがサードパーティAPIの停止、遅延、またはレート制限によって失敗する場合、それはコードの問題ではありません。依存関係の問題です。解決策は、単体テストが毎回同じように実行されるようにHTTPレイヤーをモックすることであり、Node開発者のほとんどが使用するnpmパッケージはnockです。このガイドでは、nockとは何かを説明し、小さな動作例を示し、プロセス内インターセプションよりも共有モックサーバーの方が適している場合について説明します。完全なライブラリリファレンスについては、nock GitHubリポジトリが信頼できる情報源です。
nockとは?
nockは、Node.js用のHTTPサーバーモックおよび期待値ライブラリです。これは、Nodeのhttpおよびhttpsモジュールをランタイムでオーバーライドすることにより機能し、コードが行うすべての外部リクエストをインターセプトして、事前に用意された応答で返すことができます。あなたのマシンから何も送信されません。ネットワーク呼び出しは決して発生しません。
これは単体テストにとって重要です。外部APIを呼び出す関数をテストする場合、実際のサービスにアクセスしたくありません。実際の呼び出しは遅く、費用がかかり、コードとは無関係の理由で失敗する可能性があり、テストスイートを非決定的にします。nockを使用すると、「コードがこのURLにGETリクエストを行った場合、このステータスコードでこの正確なJSONを返す」と指定できます。その後、テストは関数がその応答をどのように処理するかをアサートします。
nockはNode.js専用です。ネイティブHTTPスタックにフックするため、fetch、axios、got、node-fetch、およびhttp/httpsの上に構築されたその他すべてで動作します。週に数百万回ダウンロードされており、長年にわたりバックエンドテストのデフォルトの選択肢となっています。テストでのみ実行され、本番環境では実行されないため、開発依存関係としてインストールします。
nockの小さな例
APIからユーザーを取得する関数があるとします。その関数は次のとおりです。
// user-service.js
export async function getUser(id) {
const res = await fetch(`https://api.example.com/users/${id}`);
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
return res.json();
}
次に、nockを使用してリクエストをインターセプトするテストを示します。
// user-service.test.js
import nock from 'nock';
import { getUser } from './user-service.js';
test('returns the user when the API responds', async () => {
nock('https://api.example.com')
.get('/users/42')
.reply(200, { id: 42, name: 'Ada Lovelace' });
const user = await getUser(42);
expect(user).toEqual({ id: 42, name: 'Ada Lovelace' });
});
上から下へ読んでください。nock('https://api.example.com')はインターセプトしたいホストを設定します。.get('/users/42')はメソッドとパスを照合します。.reply(200, {...})は返すステータスとボディを定義します。getUser(42)が実行されると、実際のネットワーク呼び出しが置き換えられ、代わりに事前に用意された応答が返されます。
人々がテストを忘れがちな部分であるエラーも、同じ方法でモックできます。
test('throws when the API returns 500', async () => {
nock('https://api.example.com')
.get('/users/99')
.reply(500);
await expect(getUser(99)).rejects.toThrow('Request failed: 500');
});
モックが真価を発揮するのは、異常系のパスをテストする場合です。ライブAPIにオンデマンドで500エラーを確実に返させることはできませんが、1行でそれを偽装できます。エラーシミュレーションが主な目的である場合、500内部サーバーエラー応答をモックする方法に関するこのチュートリアルでは、さらに深く掘り下げています。
知っておくべきnockの便利な機能
基本を乗り越えると、いくつかのメソッドが常に登場します。
.persist()は、複数の呼び出しにわたってインターセプターを有効に保ちます。デフォルトでは、nockはインターセプターが1回一致すると削除します。これは、リクエストが正確に1回発生したことをアサートするのに最適です。1つのテストで同じエンドポイントが繰り返しヒットする場合に.persist()を使用します。.times(n)は、インターセプターが期限切れになる前に、同じリクエストを一定回数一致させます。.delay(ms)は、タイムアウト処理をテストできるように、遅い応答をシミュレートします。- 正規表現によるマッチングを使用すると、ホストまたはパスを固定文字列ではなくパターンにすることができ、IDやクエリ文字列が変化する場合に便利です。
nock.cleanAll()は、すべてのインターセプターをクリアします。あるテストのモックが次のテストに漏洩しないように、テスト間に実行します。
早期に身につけておくべき習慣の1つは、すべてのモックが実際に使用されたことをアサートすることです。インターセプターでscope.done() (またはnock.isDone()) を呼び出すと、期待されるリクエストが一度も発生しなかった場合にテストが失敗します。これにより、サイレントに見過ごされた呼び出しが明確な失敗に変わります。
nockが適切なツールではなくなる場合
nockは、単一のNodeプロセス内で自動テスト中にHTTPをインターセプトするという1つのタスクのために構築されており、その役割をうまくこなします。しかし、ニーズがプロセスの境界を越えた瞬間、そのモデルは限界に達し始めます。
ここに制限があります。nockのモックは、テストファイル内、ランタイム内、および使用している言語内に存在します。フロントエンド開発者は、自分のブラウザをnockの設定に向けることはできません。モバイルエンジニアは、シミュレーターからそれにアクセスすることはできません。QAチームは、それに対して手動チェックを実行することはできません。Postmanコレクションもそれにアクセスすることはできません。モックは、JestまたはMochaプロセスが実行されている間のみ存在し、その同じプロセス内のコードに対してのみ存在します。
これは単体テストにとっては問題なく、nockが設計されたまさにその目的です。しかし、誰もがアクセスできる場所に存在するモックが必要となる実際の状況も多くあります。
- バックエンドが存在する前に、フロントエンドがエンドポイントに対して構築する必要がある。
- 異なるリポジトリの3つのチームが、同じ偽の応答について合意する必要がある。
- ライブバックエンドなしでインテグレーションのデモを行いたい。
- テスターが、コードなしで手動でエッジケースを試したい。
これらの場合、実際のURLでリッスンし、呼び出すすべての人に応答を返すモックサーバーが必要です。両方のアイデアを比較検討している場合、モックサーバーとリアルサーバーの比較、およびAPIモックに関するより広範な説明の両方で、トレードオフが示されています。
nock 対 ホスト型モックサーバー (Apidog)
これらを競合ではなく、2つのレイヤーとして考えてください。nockは単体テスト用のコード内インターセプションを処理します。Apidogのようなツールは、単一のテストプロセス外で発生するすべてのことに対して、共有され、スキーマ駆動型のモックサーバーを提供します。多くのチームが両方を使用しています。

Apidogは、API設計から直接モックサーバーを生成します。エンドポイントとそのスキーマを定義すると、Apidogは、フィールド名と型からもっともらしいデータを生成するスマートなモックルールを使用して、ライブURLで現実的な応答を提供します。テストハーネスも、テストごとのセットアップも、言語のロックインもありません。URLを知っている人は誰でも同じ応答を得られます。
| nock | Apidogモックサーバー | |
|---|---|---|
| 実行場所 | Nodeテストプロセス内 | 実際のURLを持つホスト型サーバー |
| 最適な用途 | 単体テスト、エラーシミュレーション | 統合、手動テスト、チーム間での作業 |
| アクセスできる人 | 同じプロセス内のコード | URLを持つすべてのクライアント |
| 設定 | 各テストファイル内のコード | APIスキーマから生成 |
| 言語 | Node.jsのみ | すべてのクライアント、すべての言語 |
| リアルなデータ | 各応答を自分で記述 | スキーマとフィールド名からのスマートモック |
| 共有 | 共有不可 | チーム全体で共有 |
範囲を明確にすると:Apidogは、JestまたはMochaの単体テスト内でnockを置き換えるものではありません。単一のテストでfetch呼び出しをインターセプトし、その結果をアサートする必要がある場合、nockは依然として適切なツールです。Apidogは、他の人々や他のツールがアクセスできるアドレスにモックが必要な場合に登場します。サーバー側の実践的な例については、APIモックのテストに関する実践ガイドを参照してください。Apidogをダウンロードして、既存のOpenAPIファイルから数分でモックを起動できます。
nockの代替案
nockは、この分野で唯一のライブラリではなく、適切な選択肢はコードがどこで実行されるかによって異なります。
- MSW (Mock Service Worker)は、ブラウザのサービスワーカーとサーバーのNodeインターセプターを使用して、ネットワークレベルでリクエストをインターセプトします。同じモック定義が両方で機能するため、多くのチームが現在フルスタックJavaScriptのデフォルトとしてこれを使用しています。公式MSWドキュメントでこのモデルが説明されています。
- Jestの手動モックでは、
axiosのようなモジュールを偽のものに置き換えることができます。これは小規模なケースではnockよりもシンプルですが、1つのHTTPクライアントに縛られます。Jestモックチュートリアルでこのパターンが説明されています。 - Node独自のテストランナーやSinonのようなライブラリの組み込みテストダブルは、呼び出しを行う関数をスタブ化できますが、nockのHTTPレベルのマッチングは失われます。
決定的な質問は常に同じです。1つのプロセス内でロジックをテストしているのか、それともネットワーク上に存在する偽のAPIが必要なのか。nockとMSWは前者に応答します。ホスト型モックサーバーは後者に応答します。
よくある質問
nockは無料ですか?
はい。nockはMITライセンスの下でオープンソースであり、npmから無料でインストールできます。開発依存関係として追加し、テストスイートで無料で利用できます。
nockはfetchとaxiosで動作しますか?
はい。nockはNodeのhttp/httpsレイヤーでインターセプトするため、ネイティブのfetch、axios、got、node-fetchを含む、これらのモジュールの上に構築されたすべてのクライアントで動作します。コードがどのクライアントを使用しているかに関係なく、同じインターセプターを記述します。
nockをブラウザで使用できますか?
いいえ。nockはNode.js専用です。NodeのHTTPモジュールにパッチを適用するため、ブラウザには存在しません。ブラウザ側のモックには、MSWを使用するか、フロントエンドをホスト型モックサーバーに向けるようにしてください。JavaScriptにおけるモックAPIの概要では、ブラウザのオプションについて説明しています。
nockとモックサーバーの違いは何ですか?
nockはテストプロセス内でリクエストをインターセプトし、実際のポートを開くことはありません。モックサーバーは、すべてのクライアントが呼び出すことができる実際のURLでリッスンします。単体テストにはnockを使用し、フロントエンド、QA、または他のチームが同じ偽の応答にアクセスする必要がある場合はモックサーバーを使用します。
まとめ
nockは、Node.jsの単体テストにおけるHTTPモックの信頼できる選択肢です。プロセス内で送信されるリクエストをインターセプトし、定義した応答を返し、ライブAPIに対してはトリガーできないエラーパスを含め、テストスイートを高速かつ決定的にします。この目的のために引き続き使用してください。
モックがテストファイルから離れる必要がある場合、フロントエンド、QA、または別のチームが同じエンドポイントにアクセスする必要がある場合は、代わりに共有モックサーバーを利用してください。Apidogは、APIスキーマからモックを生成し、ライブURLで現実的なデータを提供するため、バックエンドが準備できる前に全員が同じ契約に基づいて構築できます。Apidogをダウンロードして、OpenAPI仕様を数分で動作するモックに変換してください。
