Jestのjest.fn()とjest.spyOn()関数について

mockingとは

単独テストコードを作成する際、該当のコードが依存する部分を偽の動きをするもの(mock)に変更すること。テスト対象のコードが依存する部分を直接作成することが難しい場合mockingする。

jest.fn()の使用方法

jestでは偽の関数を作成するjest.fn()関数を提供している。

const mockFn = jest.fn()

この偽の関数は引数をもって呼び出すことも可能である。

mockFn()
mockFn(1)
mockFn("a")
mockFn([1, 2], { a: "b" })

しかしこのままだと、偽の関数は何も設定してないためundefinedをreturnする。
mockReturnValue(return値)を利用して偽の関数がどの値をreturnすべきかを設定することができる。

mockFn.mockReturnValue("I am a mock!")
console.log(mockFn()) // I am a mock!

非同期処理をする偽の関数を作りたればmockResolvedValue(return値)を利用することができる。

mockFn.mockResolvedValue("I will be a mock!")
mockFn().then((result) => {
  console.log(result) // I will be a mock!
})

最後に、mockImplementation(コールバック関数)を利用すると、モックを丸ごと再構成することもできる。

mockFn.mockImplementation((name) => `I am ${name}!`)
console.log(mockFn("John")) // I am John!

これらの偽の関数は、何回呼び出されて、どんな引数が与えられたかを検証することができる。

mockFn("a")
mockFn(["b", "c"])

expect(mockFn).toBeCalledTimes(2)
expect(mockFn).toBeCalledWith("a")
expect(mockFn).toBeCalledWith(["b", "c"])

jest.spyOn()の使用方法

あるオプジェクトの中にある関数をmock化せず、該当の関数が呼び出されたか、どのように呼び出されたかを監視する方法。jest.spyOn(object, methodName)を利用することで監視する。

const calculator = {
  add: (a, b) => a + b,
}

const spyFn = jest.spyOn(calculator, "add")

const result = calculator.add(2, 3)

expect(spyFn).toBeCalledTimes(1)
expect(spyFn).toBeCalledWith(2, 3)
expect(result).toBe(5)

テスト

ここでは以下のような非同期処理をするfindOne()というメソッドをテストする。

const axios = require("axios")
const API_ENDPOINT = "https://***.***.com"

module.exports = {
  findOne(id) {
    return axios
      .get(`${API_ENDPOINT}/users/${id}`)
      .then((response) => response.data)
  },
}

やり方としては以下の方法にする。

  • テストコードでaxiosをインポートする。
  • axiosのget関数がnetworkの影響を受けないようにモックかする。
  • つまり、いつも同じ値を返す関数に変更する。

以上の方法でテストコードを書くと以下の通りである。

const axios = require("axios")
const userService = require("./userService")

test("findOne returns what axios get returns", async () => {
  axios.get = jest.fn().mockResolvedValue({
    data: {
      id: 1,
      name: "John",
    },
  }) // axiosのgetメソッドを非同期でいつも成功する値を返すモック関数にする。

  const user = await userService.findOne(1)
  expect(user).toHaveProperty("id", 1)
  expect(user).toHaveProperty("name", "John")
})

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です