LoginSignup
4
8

More than 5 years have passed since last update.

Node.js + Jest でモジュールの関数とクラスをモック化してユニットテストするサンプルコード

Last updated at Posted at 2019-04-18

概要

  • JavaScript テストフレームワークの Jest を使う
  • jest.mock を使用してモックを作成し、ユニットテストを実行する

npm init で開発用ディレクトリを用意

$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (hello) 
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /Users/me/hello/package.json:

{
  "name": "hello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes) 

Jest をインストール

$ npm install --save-dev jest

> fsevents@1.2.8 install /Users/me/hello/node_modules/fsevents
> node install

node-pre-gyp WARN Using request for node-pre-gyp https download 
[fsevents] Success: "/Users/me/hello/node_modules/fsevents/lib/binding/Release/node-v64-darwin-x64/fse.node" is installed via remote
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN hello@1.0.0 No description
npm WARN hello@1.0.0 No repository field.

+ jest@24.7.1
added 558 packages from 373 contributors and audited 850808 packages in 12.066s
found 0 vulnerabilities

$ cat package.json 
{
  "name": "hello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "jest": "^24.7.1"
  }
}

package.json の scipts.test の箇所を Jest を実行するように書き換える。

$ cat package.json 
{
  "name": "hello",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "jest"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "jest": "^24.7.1"
  }
}

サンプルコードを用意

getrandomint.js

getrandomint.js
// ランダムな値を返す関数
function getRandomInt(max) {
  return Math.floor(Math.random() * Math.floor(max));
}

module.exports = getRandomInt;

getrandomint.test.js

getrandomint.test.js
const getRandomInt = require('./getrandomint');

// ランダムな値ではテストできないので
// 指定した値を返すモック関数を作成
jest.mock('./getrandomint');
const getRandomIntMock = jest.fn((max) => {return max;});
getRandomInt.mockImplementation(getRandomIntMock);

// 指定した値が返ってくるかテスト
test('getRandomInt', () => {
  expect(getRandomInt(100)).toBe(100);
});

random.js

random.js
// ランダムな値を返すクラス
class Random {
  constructor() {
  }
  getInt(max) {
    return Math.floor(Math.random() * Math.floor(max));
  }
}

module.exports = Random;

random.test.js

random.test.js
const Random = require('./random');

// ランダムな値ではテストできないので
// 指定した値を返すモッククラスを作成
jest.mock('./random');
const getIntMock = jest.fn((max) => {return max});
Random.mockImplementation(() => {
  return {
    getInt: getIntMock,
  };
});

// 指定した値が返ってくるかテスト
test('Random.getInt', () => {
  expect(new Random().getInt(100)).toBe(100);
});

foobar.js

foobar.js
// getRandomInt 関数と Random クラスを使用する
const getRandomInt = require('./getrandomint');
const Random = require('./random');

// ランダムな数を2つ足して返す関数
function foobar(num) {
  const a = getRandomInt(num);
  const b = new Random().getInt(num);
  return a + b;
}

module.exports = foobar;

foobar.test.js

foobar.test.js
// getRandomInt 関数を読み込む
const getRandomInt = require('./getrandomint');

// ランダムな値ではテストできないので
// 指定した値を返すモック関数を作成
jest.mock('./getrandomint');
const getRandomIntMock = jest.fn((max) => {return max;});
getRandomInt.mockImplementation(getRandomIntMock);

// Random クラスを読み込む
const Random = require('./random');

// ランダムな値ではテストできないので
// 指定した値を返すモッククラスを作成
jest.mock('./random');
const getIntMock = jest.fn((max) => {return max});
Random.mockImplementation(() => {
  return {
    getInt: getIntMock,
  };
});

// getRandomInt 関数とRandom クラスを使用している foobar 関数を読み込む
const foobar = require('./foobar');

// 100を指定したら200が返ってくるかテスト
// foobar 関数の内部では getRandomInt 関数と Random クラスのモックが呼び出されている
test('foobar(100)', () => {
  expect(foobar(100)).toBe(200);
});

テストを実行する

$ npm test

> hello@1.0.0 test /Users/me/hello
> jest

 PASS  ./random.test.js
 PASS  ./getrandomint.test.js
 PASS  ./foobar.test.js

Test Suites: 3 passed, 3 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        1.64s
Ran all test suites.

今回の環境

macOS Mojave + Node.js v10.15.3 + Jest 24.7.1

$ node --version
v10.15.3

$ ./node_modules/jest/bin/jest.js --version
24.7.1

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.4
BuildVersion:   18E226

参考資料

4
8
1

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
4
8