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")
})