9

MochaSinonを使用して、node.js モジュールの単体テストを行っています。私は他の依存関係 (私が書いた他のモジュール) を正常にモックしましたが、純粋でない関数 (Math.random()や などDate.now()) をスタブ化する際に問題が発生しました。私は次のことを試しました(この質問があまりローカライズされないように簡略化されています)がMath.random()、明らかなスコープの問題のためにスタブ化されませんでした。のインスタンスはMath、テスト ファイルと の間で独立していますmymodule.js

test.js

var sinon    = require('sinon'),
    mymodule = require('./mymodule.js'),
    other    = require('./other.js');

describe('MyModule', function() {
    describe('funcThatDependsOnRandom', function() {
        it('should call other.otherFunc with a random num when no num provided', function() {
            sinon.mock(other).expects('otherFunc').withArgs(0.5).once();
            sinon.stub(Math, 'random').returns(0.5);

            funcThatDependsOnRandom(); // called with no args, so should call
                                       // other.otherFunc with random num

            other.verify(); // ensure expectation has been met
        });
    });
});

したがって、この不自然な例では、次のようにfunctThatDependsOnRandom()なります。

mymodule.js

var other = require('./other.js');

function funcThatDependsOnRandom(num) {
    if(typeof num === 'undefined') num = Math.random();

    return other.otherFunc(num);
}

Math.random()このシナリオでシノンとスタブすることは可能ですか?

4

3 に答える 3

9

はい、これは古い質問ですが、有効です。これはうまくいく答えですが、それを改善する方法についての提案を聞きたいです。

私がブラウザでこれを処理した方法は、プロキシ オブジェクトを作成することです。たとえば、ブラウザで window オブジェクトをスタブ化できないため、windowProxy というプロキシ オブジェクトを作成できます。位置を取得したい場合は、windowProxy で location と呼ばれるメソッドを作成し、windowLocation を返すか、設定します。次に、テスト時に windowProxy.location をモックします。

これと同じことを Node.js でも行うことができますが、それほど単純には機能しません。単純なバージョンは、あるモジュールが別のモジュールのプライベート名前空間をいじることができないということです。

解決策は、嘲笑モジュールを使用することです。require()モックを初期化した後、モックにモックするように指示したものと一致するパラメーターを使用して呼び出すと、require ステートメントをオーバーライドして独自のプロパティを返すことができます。

更新:完全に機能するコード例を作成しました。Githubのnewz2000/dice-tddあり、 npm から入手できます/END 更新

ドキュメントは非常に優れているので、読むことをお勧めしますが、例を次に示します。

randomHelper.js次のような内容のファイルを作成します。

module.exports.random = function() {
  return Math.random();
}

次に、乱数が必要なコードで、次のようにします。

var randomHelper = require('./randomHelper');

console.log('A random number: ' + randomHelper.random() );

すべてが正常に機能するはずです。プロキシ オブジェクトは、Math.random と同じように動作します。

require ステートメントが 1 つのパラメーターを受け入れることに注意することが重要です'./randomHelper'。そのことに注意する必要があります。

今あなたのテストでは、(私はモカとチャイを使用しています):

var sinon = require('sinon');
var mockery = require('mockery')
var yourModule; // note that we didn't require() your module, we just declare it here

describe('Testing my module', function() {

  var randomStub; // just declaring this for now

  before(function() {
    mockery.enable({
      warnOnReplace: false,
      warnOnUnregistered: false
    });

    randomStub = sinon.stub().returns(0.99999);

    mockery.registerMock('./randomHelper', randomStub)
    // note that I used the same parameter that I sent in to requirein the module
    // it is important that these match precisely

    yourmodule = require('../yourmodule');
    // note that we're requiring your module here, after mockery is setup
  }

  after(function() {
    mockery.disable();
  }

  it('Should use a random number', function() {
    callCount = randomStub.callCount;

    yourmodule.whatever(); // this is the code that will use Math.random()

    expect(randomStub.callCount).to.equal(callCount + 1);
  }
}

それだけです。この場合、スタブは常に 0.0.99999 を返します。もちろん変更できます。

于 2014-12-04T20:38:38.943 に答える
0

嘲笑しないことが問題だと確信していますかMath。この行はあまり意味がないようです:

sinon.mock(other).expects('otherFunc').withArgs(0.5).once();

あるモジュールでモックothersしますが、別のモジュールで使用します。でモック化されたバージョンが得られるとは思いませんmymodule.js。一方、スタブ Math.random はすべてのモジュールでグローバルであるため、機能するはずです。

nodeJS テストでの依存関係のモックについては、このSOもご覧ください。

于 2013-06-09T20:17:38.863 に答える