LoginSignup
9
6

More than 5 years have passed since last update.

Jestで非公開関数をモック化したい

Last updated at Posted at 2018-05-17

Jestでユニットテストを書くときにrewire.jsで非公開関数をモック化したら出来なかったので、解決策をメモとして残しておきます。

nodejsのバージョン: v9.2.1

ダメな例

テスト対象の実装

api-util.js
const promisify = require('util').promisify
const request = promisify(require('request'))
const cheerio = require('cheerio')

const getPageTitle = async (url) => {
    const res = await request(url)
    const $ = cheerio.load(res.body)
    return $('title').text()
}

module.exports = {
    getLowerTitle: async (url) => {
        const title = await getPageTitle(url)
        return title.toLowerCase()
    }
}

テストコード

api-util.test.js
const rewire = require('rewire')

test('ページタイトルが小文字で取得できること', () => {
    const apiUtil = rewire('./api-util')
    const getPageTitleMock = jest.fn(apiUtil.__get__('getPageTitle')).mockResolvedValue('Google')

    apiUtil.__set__({
        getPageTitle: getPageTitleMock
    })

    console.log(apiUtil.getPageTitle)

    expect(apiUtil.getLowerTitle('https://xxxxx.co.jp')).resolves.toBe('google')
})

テストを実行したらAssignment to constant variableのエラーが発生しました。
mochaでは発生しなかったのですが、Jestだとエラーが発生していまいます。

$ npx jest api-util.test.js
 FAIL  ./api-util.test.js
  ✕ ページタイトルが小文字で取得できること (1186ms)

  ● ページタイトルが小文字で取得できること

    TypeError: Assignment to constant variable.

      at eval (eval at __set__ (api-util.js:82:5), <anonymous>:1:14)
      at Object.__set__ (api-util.js:82:5)
      at Object.<anonymous>.test (api-util.test.js:7:13)

解決策

speedskater/babel-plugin-rewire を使うことで解決できました。

$ npm install babel-plugin-rewire

.babelrcに以下の内容を追記します。

.babelrc
{
  "env": {
    "test": {
      "plugins": ["rewire"]
    }
  }
}

babel-plugin-rewireは rewireと同じ__set____get__のインターフェースをサポートしているので、同じようにテストコード書くことができます。
またrewireと比較しても、モジュール読み込みはrequireで読み込めばよいので、少しだけスッキリします。

api-util.test.js
test('ページタイトルが小文字で取得できること', () => {
    const apiUtil = require('./api-util')
    const getPageTitleMock = jest.fn(apiUtil.__get__('getPageTitle')).mockResolvedValue('Google')

    apiUtil.__set__({
        getPageTitle: getPageTitleMock
    })

    expect(apiUtil.getLowerTitle('https://xxxxx.co.jp')).resolves.toBe('google')
})
9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6