Node.jsのテストがサードパーティAPIの停止、遅延、レート制限で失敗する場合、原因はアプリケーションコードではなく外部依存です。単体テストを毎回同じ結果にするには、HTTPレイヤーをモックします。Node開発でよく使われるnpmパッケージが nock です。この記事では、nockの基本、最小構成のテスト例、そしてプロセス内インターセプションではなく共有モックサーバーを使うべきケースを整理します。ライブラリ仕様の詳細はnock GitHubリポジトリを参照してください。
nockとは?
nockは、Node.js向けのHTTPサーバーモックおよび期待値ライブラリです。Nodeの http / https モジュールをランタイムでオーバーライドし、外部リクエストをインターセプトして、事前に定義したレスポンスを返します。
つまり、テスト中に実際のネットワーク通信は発生しません。
外部APIを呼び出す関数を単体テストする場合、ライブAPIには依存しない方が安全です。実APIは以下の理由でテストを不安定にします。
- レスポンスが遅い
- 障害やメンテナンスの影響を受ける
- レート制限に引っかかる
- テストデータが変化する
- 異常系を意図的に再現しづらい
nockを使うと、たとえば次のように定義できます。
このURLにGETリクエストが来たら、ステータス200でこのJSONを返す。
そのうえで、アプリケーションコードがそのレスポンスを正しく処理するかを検証します。
nockはNode.js専用です。NodeのHTTPスタックにフックするため、fetch、axios、got、node-fetch、および http / https の上に構築されたクライアントで利用できます。本番環境ではなくテストで使うため、通常は開発依存関係としてインストールします。
npm install --save-dev nock
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();
}
この関数は https://api.example.com/users/:id にリクエストします。テストでは実APIを呼ばず、nockでレスポンスを差し替えます。
// user-service.test.js
import nock from 'nock';
import { getUser } from './user-service.js';
test('APIが成功したらユーザーを返す', 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' });
});
ポイントは3つです。
nock('https://api.example.com')
インターセプト対象のホストを指定します。
.get('/users/42')
HTTPメソッドとパスを指定します。
.reply(200, { id: 42, name: 'Ada Lovelace' })
返すステータスコードとボディを定義します。
getUser(42) が実行されると、実際のネットワーク呼び出しは行われず、nockが定義済みレスポンスを返します。
エラーケースをテストする
モックが特に有効なのは異常系です。ライブAPIに「今だけ500を返して」と要求することはできませんが、nockなら1行で再現できます。
test('APIが500を返したら例外を投げる', async () => {
nock('https://api.example.com')
.get('/users/99')
.reply(500);
await expect(getUser(99)).rejects.toThrow('Request failed: 500');
});
このように、通常の正常系だけでなく、以下のようなケースも安定して検証できます。
- 500 Internal Server Error
- 404 Not Found
- タイムアウト
- 不正なJSON
- 空レスポンス
- レート制限レスポンス
エラーシミュレーションを重点的に扱う場合は、500内部サーバーエラー応答をモックする方法も参考になります。
テスト間でモックを掃除する
nockを使うときは、テスト間でインターセプターが残らないようにします。Jestなら afterEach で nock.cleanAll() を呼ぶのが基本です。
import nock from 'nock';
afterEach(() => {
nock.cleanAll();
});
さらに、外部通信を禁止したい場合は nock.disableNetConnect() を使えます。
beforeAll(() => {
nock.disableNetConnect();
});
afterAll(() => {
nock.enableNetConnect();
});
これにより、nockで定義していない外部HTTPリクエストが発生した場合にテストを失敗させられます。意図しないライブAPI呼び出しを防ぐのに便利です。
リクエストが本当に発生したか検証する
nockでは、モックを定義しただけでは「そのリクエストが実際に呼ばれたか」までは自動で明示されません。期待したHTTP呼び出しが行われたことを確認するには、scope.done() を使います。
test('指定したAPIを呼び出す', async () => {
const scope = nock('https://api.example.com')
.get('/users/42')
.reply(200, { id: 42, name: 'Ada Lovelace' });
await getUser(42);
scope.done();
});
scope.done() は、定義したインターセプターが消費されていない場合にテストを失敗させます。
複数のnock定義をまとめて確認したい場合は nock.isDone() も使えます。
expect(nock.isDone()).toBe(true);
このチェックを入れておくと、「テストは通っているが、実は期待したAPI呼び出しが行われていない」という見落としを減らせます。
知っておくべきnockの便利な機能
基本的な get() / reply() 以外にも、実務でよく使うメソッドがあります。
.persist()
同じインターセプターを複数回使う場合に指定します。デフォルトでは、nockのインターセプターは1回一致すると削除されます。
nock('https://api.example.com')
.persist()
.get('/health')
.reply(200, { status: 'ok' });
同じエンドポイントを何度も呼ぶテストで使えます。
.times(n)
指定回数だけ同じリクエストにマッチさせます。
nock('https://api.example.com')
.get('/users/42')
.times(2)
.reply(200, { id: 42 });
「ちょうど2回呼ばれる」ようなリトライ処理のテストに使えます。
.delay(ms)
遅いレスポンスを再現します。
nock('https://api.example.com')
.get('/slow')
.delay(3000)
.reply(200, { ok: true });
タイムアウト処理やローディング制御の検証に使えます。
正規表現によるマッチング
IDやクエリ文字列が変わる場合は、パスに正規表現を使えます。
nock('https://api.example.com')
.get(/\/users\/\d+/)
.reply(200, { id: 123, name: 'Test User' });
固定値ではなくパターンでリクエストを受けたい場合に便利です。
nock.cleanAll()
すべてのインターセプターを削除します。
afterEach(() => {
nock.cleanAll();
});
テストの独立性を保つため、テスト間で実行するのが安全です。
nockが適切なツールではなくなる場合
nockは、単一のNodeプロセス内でHTTPリクエストをインターセプトするためのツールです。単体テストでは強力ですが、モックの利用範囲がプロセス外に広がると制限が出ます。
nockのモックは以下の場所に閉じています。
- テストファイル内
- Node.jsランタイム内
- JestやMochaなどのテストプロセス内
- 使用している言語、つまりNode.js内
そのため、次のような使い方はできません。
- フロントエンド開発者がブラウザからnockのモックURLを呼ぶ
- モバイルアプリがシミュレーターからnockのモックにアクセスする
- QAチームが手動テストで同じモックを使う
- Postmanや他のAPIクライアントからnockのモックを叩く
nockは実際のサーバーを起動しません。あくまで同じNodeプロセス内のHTTP呼び出しを差し替えるだけです。
単体テストにはこれで十分です。しかし、次のようなケースでは共有モックサーバーが必要になります。
- バックエンド実装前にフロントエンド開発を進めたい
- 複数リポジトリのチームで同じAPIレスポンスを共有したい
- ライブバックエンドなしでデモを行いたい
- QAがコードを書かずにエッジケースを確認したい
- Postman、ブラウザ、モバイルアプリなど複数クライアントから同じ偽APIを叩きたい
この場合は、実際のURLでリッスンし、誰が呼んでも同じレスポンスを返すモックサーバーを使います。
比較観点は、モックサーバーとリアルサーバーの比較とAPIモックの解説でも整理されています。
nock 対 ホスト型モックサーバー(Apidog)
nockとホスト型モックサーバーは競合というより、使うレイヤーが違います。
- nock: Node.jsの単体テスト内でHTTP呼び出しをインターセプトする
- Apidog: APIスキーマから共有可能なモックサーバーを生成する
多くのチームでは、単体テストにはnock、チーム共有や手動検証にはモックサーバー、という形で両方を使います。
Apidogは、API設計からモックサーバーを生成します。エンドポイントとスキーマを定義すると、フィールド名や型をもとにレスポンスを生成し、ライブURLで返します。
テストハーネスやテストごとのセットアップは不要です。URLを知っているクライアントであれば、ブラウザ、モバイルアプリ、Postman、別言語のバックエンドなどから同じモックにアクセスできます。
| nock | Apidogモックサーバー | |
|---|---|---|
| 実行場所 | Nodeテストプロセス内 | 実際のURLを持つホスト型サーバー |
| 最適な用途 | 単体テスト、エラーシミュレーション | 統合、手動テスト、チーム間での作業 |
| アクセスできる人 | 同じプロセス内のコード | URLを持つすべてのクライアント |
| 設定 | 各テストファイル内のコード | APIスキーマから生成 |
| 言語 | Node.jsのみ | すべてのクライアント、すべての言語 |
| リアルなデータ | 各応答を自分で記述 | スキーマとフィールド名からのスマートモック |
| 共有 | 共有不可 | チーム全体で共有 |
使い分けは明確です。
JestやMochaの単体テストで fetch 呼び出しをインターセプトし、関数の戻り値や例外を検証したいならnockを使います。
一方、フロントエンド、QA、モバイル、別チーム、外部ツールが同じモックAPIにアクセスする必要があるなら、Apidogのような共有モックサーバーを使います。
サーバー側の実践例は、APIモックのテストに関する実践ガイドを参照してください。Apidogをダウンロードすれば、既存のOpenAPIファイルからモックを起動できます。
nockの代替案
nock以外にもHTTPモックの選択肢があります。選ぶ基準は「どこでコードが実行されるか」です。
MSW(Mock Service Worker)
MSWは、ブラウザではService Worker、Node.jsではNodeインターセプターを使ってリクエストをモックします。同じモック定義をブラウザとNodeで共有しやすいため、フルスタックJavaScriptでよく使われます。
詳細は公式MSWドキュメントで確認できます。
Jestの手動モック
Jestの手動モックを使うと、axios などのモジュール自体を偽物に置き換えられます。
jest.mock('axios');
小規模なケースではnockより簡単ですが、特定のHTTPクライアントに依存します。HTTPレイヤー全体をモックするのではなく、モジュール単位で差し替えるアプローチです。
このパターンはJestモックチュートリアルでも説明されています。
テストダブルやスタブ
NodeのテストランナーやSinonのようなライブラリで、HTTP呼び出しを行う関数をスタブ化する方法もあります。
ただし、この方法ではnockのようなHTTPメソッド、パス、ヘッダー、ボディに対するマッチングは失われます。関数単位の置き換えで十分な場合に向いています。
使い分けの目安
判断基準はシンプルです。
nockを使うケース
- Node.jsの単体テストを書いている
- 実ネットワーク通信を発生させたくない
-
fetchやaxiosの呼び出し結果を固定したい - 500、404、タイムアウトなどの異常系を再現したい
- テストプロセス内だけで完結すればよい
共有モックサーバーを使うケース
- ブラウザやモバイルアプリからモックAPIを呼びたい
- QAや他チームと同じモックレスポンスを共有したい
- Postmanなど外部ツールからアクセスしたい
- API契約をもとにフロントエンドとバックエンドを並行開発したい
- 実際のURLで動く偽APIが必要
nockとMSWは、主にプロセス内または開発環境内のモックに向いています。ホスト型モックサーバーは、ネットワーク上で共有する偽APIが必要な場合に向いています。
よくある質問
nockは無料ですか?
はい。nockはMITライセンスのオープンソースライブラリです。npmから無料でインストールでき、開発依存関係としてテストスイートに追加できます。
npm install --save-dev nock
nockはfetchとaxiosで動作しますか?
はい。nockはNodeの http / https レイヤーでインターセプトします。そのため、ネイティブの fetch、axios、got、node-fetch など、これらのモジュールの上で動くHTTPクライアントに対応します。
nockをブラウザで使用できますか?
いいえ。nockはNode.js専用です。NodeのHTTPモジュールにパッチを適用する仕組みのため、ブラウザには対応していません。
ブラウザ側でモックしたい場合は、MSWを使うか、フロントエンドをホスト型モックサーバーに向けます。JavaScriptにおけるモックAPIの概要でもブラウザ側の選択肢が説明されています。
nockとモックサーバーの違いは何ですか?
nockは、Node.jsのテストプロセス内でHTTPリクエストをインターセプトします。実際のポートやURLを公開するわけではありません。
モックサーバーは、実際のURLでリッスンし、ブラウザ、モバイルアプリ、Postman、他言語のサービスなど、複数のクライアントから呼び出せます。
単体テストにはnockを使い、チームやツール間で共有するモックAPIが必要な場合はモックサーバーを使います。
まとめ
nockは、Node.jsの単体テストでHTTPリクエストをモックするための実用的な選択肢です。プロセス内で外部リクエストをインターセプトし、定義したレスポンスを返すことで、テストを高速かつ決定的にできます。特に、ライブAPIでは再現しづらい500エラー、404、タイムアウトなどの異常系テストに向いています。
一方、モックをテストファイルの外に出し、フロントエンド、QA、モバイル、他チームと共有したい場合は、共有モックサーバーを使います。ApidogはAPIスキーマからモックを生成し、ライブURLでレスポンスを提供します。Apidogをダウンロードして、OpenAPI仕様を動作するモックに変換できます。

Top comments (0)