🐣
Jestの__mocks__ディレクトリに気づかずハマった話 〜モックが勝手に値を返す理由〜
記事の概要
Jestのマニュアルモックの仕様をよく理解していなかったため、「mockReturnValueなどを設定していないのに、どうして値が返ってくるのだろう?」と疑問に思い、少し混乱してしまいました。そこで、その体験を忘れないよう忘備録としてこの記事を書きました。
特に、__mocks__
ディレクトリの役割について簡単に説明しています。
混乱した内容
プロダクトコード(サンプル)
概要だけ知りたい方は読み飛ばしていただいて大丈夫です。
プロダクトコード
src/modules/fetchMonster.js
const axios = require("axios");
// { race: "slime" } というオブジェクトを返す
module.exports = fetchMonster = async () => {
const response = await axios.get("url");
return response.data;
};
src/modules/nameMonster.js
module.exports = nameMonster = (race) => {
switch (race) {
case "slime":
return "リムール";
case "goblin":
return "ゴブータ";
default:
const num = Math.floor(Math.random() * 100) + 1;
return `ナンバー${num}`;
}
};
src/index.js
const fetchMonster = require("./modules/fetchMonster.js");
const nameMonster = require("./modules/nameMonster.js");
module.exports = createNamedMonster = async () => {
const monster = await fetchMonster();
monster.name = nameMonster(monster.race);
return monster;
};
テストコード(サンプル)
fetchMonster
:APIを通じてモンスターを取得する関数
createNamedMonster
:モンスターを取得し、名前をつける関数
mockResolvedValue
を使ってモックに値を設定していないのに、テストが通っていたので混乱しました。(fetchMonsterの値が返ってきていました)
src/index.test.js
const createNamedMonster = require("./index.js");
const fetchMonster = require("./modules/fetchMonster.js");
jest.mock("./modules/fetchMonster.js");
test("モンスターの種族がスライムの場合、「リムール」と名付けられること", async () => {
const expectedMonster = {
race: "slime",
name: "リムール",
};
- const mockMonster = {
- race: "slime",
- };
- fetchMonster.mockResolvedValue(mockMonster);
const actual = await createNamedMonster();
expect(actual).toEqual(expectedMonster);
});
なぜ値が返ってきていたのか
Jestでは、__mocks__
というディレクトリを使ってモックを管理することが可能です。jest.mock
を実行すると、モジュールと同じディレクトリにある__mocks__
配下の同名ファイル(モック)が自動的に読み込まれます。このため、モックが設定されていないように見えても値が返ってきていたのです。
サンプルのテストが通っていたのも、以下のモックが存在していたことで値が返ってきていたからです。
src/modules/__mocks__/fetchMonster.js
module.exports = fetchMonster = async () => {
return {
race: "slime",
};
};
詳しくは、Jestの公式ドキュメントをご覧ください。
Discussion