テストフレームワークを利用する場合に気を付けること（コード設計）

# はじめに。

モックなどへ差し替えが効く場所と、効かない場所でハマったのでメモ。
それから派生して、UTテストフレームを利用する場合に気にすべき
**元コードの設計**観点など。


# テスト対象ファイル内の関数は差し替え出来ない。

require() されるファイルで定義されたインスタンスは触れないみたい。
sinon でStub化を試みてもダメ。

たとえば、以下のようなソースファイル stub_trial.js のテストにおいて、
a:function(){} を差し替えようとしても、出来ない。
**元の関数が呼ばれてしまう**。
（カプセル化の観点から考えれば、妥当なんですが）

```js:stub_trial.js
var a = function( argv ){
    console.log( "[a()] is called with \"" + argv +"\"" );
    return argv;
}

var z = function( key ){
    return a( key );
}

exports.a = a;
exports.z = z;
```

上記に対するテストコード。
b() をテストするときは、a()をスタブに差し替えを試みているが、**NG**。

```js:stub_trial_test.js
const chai = require("chai");
const assert = chai.assert;
const expect = chai.expect;
const sinon = require("sinon");
const stub_trial = require("../src/stub_trial.js");

describe( "require先の関数をstub化できる？", function(){

    describe( "#z()のテスト。内部でa()が呼ばれている", function(){
        it(" normal test." ,function(){
            expect(
                stub_trial.z("test"), "just called."
            ).to.equal( "test" );
        });

        it(" stub test.", function(){ // ⇒やっぱ出来ないみたい。
            var stub = sinon.stub( stub_trial, "a" );
            stub.withArgs("test").returns( "stub!" );

            expect(
                stub_trial.z("test"), "with stub."
            ).to.equal( "stub!" );
        });
    });

});
```

require() されるファイル一括単位であれば方法はあるみたい？
試してないので詳しくは分らないけど。


# 対応策⇒差替えたい関数はStrategy パターン にしておく。

UTテストフレームを利用で困らないためには、差替えたい関数には
Strategy パターン を適用しておく。
こうしておくと、差し替えが容易に出来る。
さもないと、**困難度が跳ね上がる**ことがあるので注意。

なお、**外部環境依存**や**外部出力**などの「副作用を持つ」
関数は差替えた方がUTが楽な場合が多い。
なので、「副作用を持つ関数には、Strategyパターン適用」しておく方針。

イメージとしては以下。

```js:stub_strategy.js
var a_strategy_out_external_effect = function( argv ){
    console.log( "[a()] is called with \"" + argv +"\"" );
    return argv;
}

var b = function( str ){ return "[" + str + "]"; };

var z1 = function( a_strategy_out_external_effect, key ){
    return a( key );
}

var z2 = function( key ){
    return b( key );
}

exports.a_strategy_out_external_effect = a_strategy_out_external_effect;
exports.b = b;
exports.z1 = z1;
exports.z2 = z2;
```

これをテストするコードは以下。
z1() をテストするときは、a_strategy_out_external_effect() をスタブ化出来る。

```js:stub_strategy_test.js
const chai = require("chai");
const assert = chai.assert;
const expect = chai.expect;
const sinon = require("sinon");
const stub_trial = require("../src/stub_strategy.js");

describe( "require先の関数をstub化できる？with strategy", function(){

    describe( "#z()のテスト。内部でa()が呼ばれている", function(){
        it(" normal test." ,function(){
            expect(
                stub_trial.z1( stub_trial.a_strategy_out_external_effect, "test"), "just called."
            ).to.equal( "test" );
        });

        it(" stub test.", function(){ // ⇒これならOK。
            var stub = sinon.stub( stub_trial, "a_strategy_out_external_effect" );
            stub.withArgs("test").returns( "stub!" );

            expect(
                stub_trial.z1( stub, "test"), "with stub."
            ).to.equal( "stub!" );
        });
    });

    describe( "#z2()のテスト。内部で、外部への副作用の無いb()が呼ばれている", function(){
        it("normal test", function(){
            expect( stub_trial.z2("test"), "just called." )
            .to.equal( "[test]" );
        });
    });
});
```

なお、副作用（コンソールやファイル出力などの外部への影響）が無い
「 `b()` 」のような関数については、上記の考慮は不要。
普通に上の関数 `z2()` からテストすればよい。

要は
「外部環境に依存するヤツで、テスト時にそれを準備するのが手間、
　な関数には Strategy パターン を適用しておくと、UTが楽！」
ってことだね。





# 参考にしたページ
[sinon のメソッド（公式）]
http://sinonjs.org/docs/

[proxyquireでNode.jsのrequireをモックする - ジンジャー研究室]
http://jinjor-labo.hatenablog.com/entry/2015/03/20/140617

[Node.jsでmochaやproxyquireを使った単体テストをやってみたメモ - Qiita]
http://qiita.com/toshihirock/items/67e51303318d5a6030cd

[モックテストについていくらか調べた]
http://chikuwa-parfait.tumblr.com/post/137752419523/%E3%83%A2%E3%83%83%E3%82%AF%E3%83%86%E3%82%B9%E3%83%88%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%84%E3%81%8F%E3%82%89%E3%81%8B%E8%AA%BF%E3%81%B9%E3%81%9F