nodejsでfetchが入っているモジュールの単体テスト
nodejs上でfetchを使い、別のサーバーにRESTコールを投げる場合があります。
そのようなコードを単体テストする際に、実際に他のサーバーに処理を投げると他サーバーに引きずられてテストが不安定になるため、モックにしたいところです。
そこで、fetch-mock というライブラリを利用してモックする手順についてまとめました。
fetch-mock
fetch-mockはfetchを独自のモックに置き換え、指定したレスポンスを返すように設定できるライブラリです。
グローバルfetchを使う場合の使い方
fetch-mockのデフォルトの挙動では、グローバルオブジェクトに登録されているfetchを置き換えてくれます。公式サイトにも載っているサンプルを元に説明します。
nodeではネイティブでfetchがglobalオブジェクトには紐付いておらず、この方法は使えません。nodeでは別途後述するsandboxメソッドを使わないとだめですが、挙動はほぼ変わらないので、まずはfetch-mockの本来の使い方について触れます。
module.exports = function makeRequest() {
return fetch("http://httpbin.org/get").then(function(response) {
return response.json();
});
};
httpbin.org/get
に対してgetリクエストを出して、そのレスポンスをJSONパースしてオブジェクトとして返します。httpbin.org/get
のエンドポイントは実在していて、モックせずにfetchするとちゃんとしたレスポンスが返ってきます。
このソースコードに対するテストとして下記のようなテストを書きます。
var fetchMock = require('fetch-mock');
var makeRequest = require('./make-request');
// Mock the fetch() global to always return the same value for GET
// requests to all URLs.
fetchMock.get('*', {hello: 'world'});
makeRequest().then(function(data) {
console.log('got data', data);
});
// Unmock.
fetchMock.restore();
fetchMock.get
によりグローバルのfetchオブジェクトをfetchMockが作ったモックに置き換えています。
第一引数は対象のURLを示しており、このサンプルでは*
にしているため、全てのURLが対象になります。
第二引数はレスポンスを示していて、{hello:'world'}
というJSONをレスポンスとして返します。
この状態でfetchを呼ぶと、どのURLに対してアクセスしても第二引数のレスポンスが返ってきます。
実際に実行すると下記のようになります。
$ node mocked.js
'got data' { hello: 'world' }
非グローバルなfetchを使うやり方
nodeを使っている場合、前述した通りfetchはグローバルオブジェクトには紐付いておらず、node-fetchなどを持ってくる必要があります。。make-request.js
でいうと、例えば下記のようなコードになります。
var fetch = require('node-fetch')
module.exports = function makeRequest() {
return fetch("http://httpbin.org/get").then(function(response) {
return response.json();
});
};
ここで使うfetchはグローバルなものではないので、fetchMockでmockしても置き換わってくれません。
そこで、sandboxというメソッドを使ってモックを作り出します。作り出したモックは任意のスタブ組み込みライブラリで組み込む必要があります。
ここではproxyquireをスタブ組み込みライブラリとして使用します。
var fetchMock = require('fetch-mock');
var proxyquire = require('proxyquire')
var myMock = fetchMock.sandbox().mock('*',{hello: 'world'});
var makeRequest = proxyquire('./make-request-node-fetch',{
'node-fetch': myMock
});
makeRequest().then(function(data) {
console.log('got data', data);
}).catch((e) => { console.log(e.message)});
proxyquireを使ってmake-request.js内でのrequire('node-fetch')
で返ってくるfetchメソッドをモックしています。
proxyquireは今回ちょろっと紹介しただけですが、これも非常に便利なのでテストに多用できると思います。