6

次の単体テストコードでは、次のようになります。

TestModel = Backbone.Model.extend({
    defaults: {
        'selection': null
    },
    initialize: function() {
      this.on('change:selection', this.doSomething);
    },
    doSomething: function() {
        console.log("Something has been done.");
    }
});

module("Test", {
    setup: function() {
        this.testModel = new TestModel();
    }
});

test("intra-model event bindings", function() {
    this.spy(this.testModel, 'doSomething');
    ok(!this.testModel.doSomething.called);
    this.testModel.doSomething();
    ok(this.testModel.doSomething.calledOnce);
    this.testModel.set('selection','something new');
    ok(this.testModel.doSomething.calledTwice); //this test should past, but fails.  Console shows two "Something has been done" logs.
});

コンソールによってデモされたように、関数がバックボーンイベントバインディングから効果的に呼び出されたにもかかわらず、3番目のokは失敗します。

3番目のテストは失敗します ここに画像の説明を入力してください

これは非常に苛立たしいことであり、sinon.jsが私のバックボーンアプリのテストに適しているかどうかについての私の自信を揺るがしました。私は何か間違ったことをしていますか、それともこれは何かが呼び出されたかどうかをsinonが検出する方法の問題ですか?回避策はありますか?

編集:受け入れられた答えのモンキーパッチ法に基づいた、私の特定の例に対する解決策があります。テスト自体に数行の追加のセットアップコードがありますが(モジュール関数はもう必要ありません)、作業は完了します。ありがとう、mu is too short

test("intra-model event bindings", function() {
    var that = this;
    var init = TestModel.prototype.initialize;
    TestModel.prototype.initialize = function() {
        that.spy(this, 'doSomething');
        init.call(this);
    };

    this.testModel = new TestModel();
    . . . // tests pass!
}); 
4

1 に答える 1

12

呼び出すと、メソッドが新しいラッパーメソッドthis.spy(this.testModel, 'doSomething')に置き換えられます。testModel.doSomething

var spy = sinon.spy(object、 "method");

のスパイを作成しobject.method、元のメソッドをスパイに置き換えます。

したがってthis.spy(this.testModel, 'doSomething')、効果的に次のようなことを行っています。

var m = this.testModel.doSomething;
this.testModel.doSomething = function() {
    // Spying stuff goes here...
    return m.apply(this, arguments);
};

これは、 :testModel.doSomethingでイベントハンドラーをバインドするときの別の関数であることを意味します。initialize

this.bind('change:selection', this.doSomething);

スパイを付けた後よりも。バックボーンイベントディスパッチャは元のdoSomethingメソッドを呼び出しますが、そのメソッドにはSinonインストルメンテーションがありません。doSomething手動で呼び出す場合は、spy追加された新しい関数を呼び出しており、その関数にはSinonインストルメンテーションがあります。

Sinonを使用してバックボーンイベントをテストする場合は、spyイベントハンドラーをバインドする前に、モデルにSinon呼び出しを適用するように調整する必要があります。これは、おそらくにフックすることを意味しinitializeます。

モデルにモンキーパッチを適用して、イベントハンドラーをバインドする前にinitialize、必要な呼び出しを追加できるかもしれません。spy

var init = Model.prototype.initialize;
Model.prototype.initialize = function() {
    // Set up the Spy stuff...
    init.apply(this, arguments);
};

デモ: http: //jsfiddle.net/ambiguous/C4fnX/1/

次のようなものでモデルをサブクラス化することもできます。

var Model = Backbone.Model.extend({});
var TestModel = Model.extend({
    initialize: function() {
        // Set up the Spy stuff...
        Model.prototype.initialize.apply(this, arguments);
    }
});

そして、Modelの代わりに使用すると、通常の本番環境に対応したテスト固有のコードを多数含めることなくTestModel、インストルメント化されたバージョンのModelinが提供されます。欠点は、使用する他のものはすべて、代わりに使用するためにサブクラス化/パッチ適用/...する必要があるということです。TestModelModelModelTestModel

デモ: http: //jsfiddle.net/ambiguous/yH3FE/1/

TestModel次の方法で問題を回避できる可能性があります。

var OriginalModel = Model;
Model = Model.extend({
    initialize: function() {
        // Set up the Spy stuff...
        OriginalModel.prototype.initialize.apply(this, arguments);
    }
});

Modelただし、すべての人が古いものではなく新しいものを使用していることを確認するには、順序を正しくする必要があります。

デモ: http: //jsfiddle.net/ambiguous/u3vgF/1/

于 2012-06-02T20:11:28.070 に答える