web-dev-qa-db-ja.com

イベントが発生した後に関数が呼び出されたことをテストするにはどうすればよいですか?

FooViewで発生するカスタムイベントがあります。

// views/foo_view.js

this.trigger("something:happened");

関連するFooControllerは、イベントを処理するためにハンドラーをバインドします...

// controller/foo_controller.js

initialize: function() {
  this.fooView = new FooView();
  this.fooView.bind("something:happened", this.onSomethingHappened, this);
}

onSomethingHappened: function(event) {
  // Do something else.
}

イベント処理をテストするには、 Jasmine に対して次のテストを記述します。

it("should do something else when something happens", function() {
  var fooController = new FooController();
  spyOn(fooController, "onSomethingHappened");
  fooController.fooView.trigger("something:happened");
  expect(fooController.onSomethingHappened).toHaveBeenCalled();
});

しかし、テストは失敗します..

FooView should do something else when something happens.
Expected spy onSomethingHappened to have been called.
Error: Expected spy onSomethingHappened to have been called.
    at new jasmine.ExpectationResult (http://localhost:8888/__JASMINE_ROOT__/jasmine.js:114:32)
    at null.toHaveBeenCalled (http://localhost:8888/__JASMINE_ROOT__/jasmine.js:1235:29)
    at null.<anonymous> (http://localhost:8888/assets/foo_spec.js?body=true:225:47)
    at jasmine.Block.execute (http://localhost:8888/__JASMINE_ROOT__/jasmine.js:1064:17)
    at jasmine.Queue.next_ (http://localhost:8888/__JASMINE_ROOT__/jasmine.js:2096:31)
    at jasmine.Queue.start (http://localhost:8888/__JASMINE_ROOT__/jasmine.js:2049:8)
    at jasmine.Spec.execute (http://localhost:8888/__JASMINE_ROOT__/jasmine.js:2376:14)
    at jasmine.Queue.next_ (http://localhost:8888/__JASMINE_ROOT__/jasmine.js:2096:31)
    at onComplete (http://localhost:8888/__JASMINE_ROOT__/jasmine.js:2092:18)
    at jasmine.Spec.finish (http://localhost:8888/__JASMINE_ROOT__/jasmine.js:2350:5)

イベントが実行するのに予想よりも時間がかかるため、テストは失敗しますか?

12
JJD

問題は、関数がイベントにバインドされた後に関数をスパイすることです。ジャスミンがスパイを作成すると、スパイした機能が別の機能に置き換えられます。

つまり、ここで何が起こるかというと、元の関数はイベントにバインドされているということです。

this.fooView.bind("something:happened", this.onSomethingHappened, this);

その後、元の関数はスパイに置き換えられますが、それはbind関数に渡す関数には影響しません。

その解決策は、新しいインスタンスを作成する前にFooController.prototype.onSomethingHappenedをスパイすることです。

it("should do something else when something happens", function() {
  var onSomethingHappenedSpy = spyOn(FooController.prototype, "onSomethingHappened");
  var fooController = new FooController();
  fooController.fooView.trigger("something:happened");
  expect(onSomethingHappenedSpy).toHaveBeenCalled();
});
17