Posted at

Node.jsのテストでJestを使ってfetchをモックするのは意外に大変

opengraph.png

Jestを使ってfetch()をモックしたかったです。

いくつかのハマりポイントでハマってしまったのですが解決できました。


Jestの初期化

Jest本体とBabel、今回テストを行いたいnode-fechのモジュールを入れます。

リポジトリを初期化しておきます。

$ yarn init

BabelはJestのテストファイルでimport文などのES6記法を使うために入れています。

$ yarn add --dev jest babel-core babel-jest babel-plugin-transform-es2015-modules-commonjs node-fetch


.babelrc

{

"env": {
"test": {
"plugins": [
"transform-es2015-modules-commonjs"
]
}
}
}


テストファイルを置く

テストコードを先に書いてしまいます。


index.test.js

import fetch from 'node-fetch'

jest.mock('node-fetch', () => jest.fn())

describe('fetch-mock test', () => {
it('check fetch mock test', async () => {
const dummyResponse = Promise.resolve({
ok: true,
status: 200,
json: () => {
return {};
},
});

fetch.mockImplementation(() => dummyResponse)
await dummyResponse;

console.log(dummyResponse);
});
});


動かしてみます。

image.png


テスト対象コード


index.js

'use strict'

var fetch = require('node-fetch');

const makeRequest = async () => {
const res = await fetch("http://httpbin.org/get");
const resJson = await res.json();
return resJson;
};

module.exports = makeRequest;



index.test.js

import fetch from 'node-fetch'

jest.mock('node-fetch', () => jest.fn())

describe('fetch-mock test', () => {
it('check fetch mock test', async () => {
const dummyResponse = Promise.resolve({
ok: true,
status: 200,
json: () => {
return {};
},
});
fetch.mockImplementation(() => dummyResponse)
await dummyResponse;

var makeRequest = require('./index'); // テストしたいモジュールを読み込む

makeRequest().then(function (data) { // success
console.log('got data', data); // ダミーレスポンスが帰ってきている
}).catch((e) => { // error
console.log(e.message)
});
});
});


jest.mock('node-fetch', () => jest.fn())をすることで、本体コード側でnode-fetchjestのモックモジュールに置き換える宣言をしています。

fetch.mockImplementation(() => dummyResponse)で実際にどんなレスポンスを返すかの実装を行っています。

うまく動きました!


ハマったポイント


proxyquire

JavaScriptのモック用ライブラリにproxyquireがあります。

テストするときには非常に協力なモックライブラリで、具体的にはrequireを良い感じに乗っ取ってモックされた関数などを返します。

proxyquireでDI もっとモックテストしよう

ただJestとの相性がよくないらしく、Jestではproxyquireが動かない、という報告がありました。

Does not work with proxyquire

実際に今回は動きませんでした。このIssueではjest.mockを使え、となっていますね。

proxyquire自体も古い1ようで、Jestではjest.mockを使っていくほうが良いようです。


nock

fetchのモックするためのライブラリにnockがあります。こちらも良く出来たライブラリなのですが、うまく動きませんでした。

【Node.js】nockでtest!


jest-fetch-mock

Jest用のfetchをモックする専用のライブラリ jest-fetch-mock があります。

jest.mock()汎用のモックシステムなのですが、fetchレスポンスにフォーカスしたライブラリのようです。

こちらもうまく動かせませんでした。


謝辞

今回の件でうまく動かせず色々ヘルプをもらいました。

@say3no @ketch123 @ur0n @naname

ありがとうございました!

StackOverFlowで回答してくれたAndreas Köberleありがとう!

How can I mock fetch function in Node.js by Jest?





  1. 2018年現在では2015年ぐらいの記事が多かったです。