Help us understand the problem. What is going on with this article?

Javascript + sinon スタブの実践的利用

tl;dr

完成した関数をテストしたいが、未完成の関数をコールしているのでunit testができない。
その場合の対処です。

確認環境

  • node: v10.17.0
  • npm: 6.11.3

プロジェクトの準備

以下のコマンドを実行します。

mkdir play_utest
cd play_utest
npm init
npm i --save-dev chai mocha sinon
touch index.js index.spec.js

package.jsonを変更します。

{
  "name": "play_utest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
-   "test": "echo \"Error: no test specified\" && exit 1"
+   "test": "mocha *.spec.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "chai": "^4.2.0",
    "mocha": "^6.2.2",
    "sinon": "^7.5.0"
  }
}

テスト対象のコード

index.jsを編集します。
main()関数が単体テストの対象(SUT)です。
doubleNumber()をコールしていますが、この関数はまだ中身を作っていません。

index.js
const doubleNumber = (x) => {
  // ここに、xを2倍にして返すロジックを書く予定 
  return 0; // 暫定
}

const main = (x) => {
  const answer = doubleNumber(x);
  return answer + 1;
}
module.exports.main = main

テストコード

index.spec.jsを編集します。

index.js
const sinon = require("sinon");
const expect = require("chai").expect;
const index = require('./index.js');

describe('index.js', () => {
  it('main(n)のテスト: n = {0, 5, -1}', () => {
    expect(index.main(0)).equal(1)
    expect(index.main(5)).equal(11) 
    expect(index.main(-1)).equal(-1)
  })
})

main()関数の引数に、{0, 5, -1}を渡したケースで単体テストを行いたいと考えています。
doubleNumber()関数は、暫定的に0を返すようにしているため、引数0のケースだけテストが成功しそうですが、それ以外のケースだと想定する結果になりません。

テスト対象コードを、テスト向けにリファクタ

doubleNumberをテストスタブに置き換えるため、クラスでラップします。このクラスもmodule.exportsを使って外部公開します。

index.js
const doubleNumber = (x) => {
  // ここに、xを2倍にして返すロジックを書く予定 
  return 0; // 暫定
}

const main = (x) => {
-  const answer = doubleNumber(x);
+  const answer = helpers.doubleNumber(x);
  return answer + 1;
}
module.exports.main = main

+ class Helpers{
+   doubleNumber(x) { return doubleNumber(x) }; 
+ }
+ const helpers = new Helpers();
+ module.exports.helpers = helpers;

テストコードを変更

doubleNumber()のスタブを作成します。

index.spec.js
const sinon = require("sinon");
const expect = require("chai").expect;
const index = require('./index.js');

describe('index.js', () => {
  it('main(n)のテスト: n = {0, 5, -1}', () => {
+   const stub = sinon.stub(index.helpers, 'doubleNumber');
+   stub.withArgs(0).returns(0);  // 引数が0の時、0を返す
+   stub.withArgs(5).returns(10);  // 引数が5の時、10を返す
+   stub.withArgs(-1).returns(-2);  // 引数が-1の時、-2を返す

    expect(index.main(0)).equal(1)
    expect(index.main(5)).equal(11)
    expect(index.main(-1)).equal(-1)
  })
})

テストの実行

以下のコマンドでテストを実行します。

npm test

結果:

> mocha *.spec.js

  index.js
    ✓ main(n)のテスト: n = {0, 5, -1}

  1 passing (11ms)
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした