Jestによるmock入門

どうも。FF7聖剣伝説3の両リメイクが待ち遠しい大庭です。

今回は、JavaScriptのテストツールのJestでのmockについての話です。
Jestでテスト書くのが初めてだったので、入門向けの話になりますのでご容赦を。

今回のテスト対象の擬似コード

こんな感じの関数(myFunc.js)をテストしたいとします。

const axios = require('axios')
const function1 = require('./function1')
const function2 = require('./function2')
const function3 = require('./function3')

module.exports = () => {
  const users = await axios.get('/users.json')
  const someResult = function1()

  let result

  if (someResult) {
    result = function2()
  } else {
    result = function3(users)
  }

  return { users: users, infos: result }
}

この関数をテストするためにJestのmockをどう利用していくかを紹介していきます。

モジュールをmock化したい

自分で定義したfunction1や利用しているライブラリをmock化したい場合は下記のようにします。

jest.mock('./function1')
jest.mock('axios')

このように記述するだけで、自動的にこれらを読み込んだ場合はmock化されます。

mockの戻り値を定義したい

mockの戻り値を定義したい場合は下記のように書きます。 (他の書き方もありますが

jest.mock('./function1',  () => {
  return jest.fn(() => true);
})

テストケースによってmockの戻り値を変えたい

これはもっといい書き方があるのではと思っているのですが、現状は下記のようにしています。

jest.mock('./function1')

describe('function1', () => {
  it('case 1', () => {
    function1.mockReturnValue(true)
    expect(・・・)
  })
  it('case 2', () => {
    function1.mockReturnValue(false)
    expect(・・・)
  })
})

Promiseを返す非同期関数の場合はmockResolvedValueを使います。

関数が呼ばれたかをチェックしたい

mock化するとtoBeCalledなどのマッチャーを利用することができるようになります。

const myFunc = require('./')

jest.mock('axios')
jest.mock('./function1')
jest.mock('./function2')
jest.mock('./function3)

describe('myFunc', () => {
  it('case 1', () => {
    function1.mockReturnValue(true)
    myFunc()

    expect(function2).toBeCalled()
    expect(function3).not.toBeCalled()
  })
  it('case 2', () => {
    function1.mockReturnValue(false)
    myFunc()

    expect(function2).not.toBeCalled()
    expect(function3).toBeCalled()
  })
})

さいごに

普段の開発ではRSpecを利用しているので、RSpecだったらこんな場合すぐ書けるのにJestだとどう書いたらいいんだー!!と初めの内は思っていましたが、慣れてくるとそこそこ書けるようになってきました。
Jestにはスナップショットなど他にも便利な機能があるようなので、早く「Jest、完全に理解した」と言えるように精進したいです。


あしたのチームではJestに強いエンジニアを募集しています。