LoginSignup
3
2

More than 5 years have passed since last update.

Emberのunit testでstoreオブジェクトをstubにしたらrestoreも忘れずに

Posted at

Emberに限った話でもないですが、少しハマったので

はじめに

以下のようなモデルがあるとします

App.User = DS.Model.extend({
  name: DS.attr('string'),
  age: DS.attr('number'),

  callUp: function() {
    var calling = this.store.createRecord('calling', userId: this.get('id'));
    calling.save().then(function() {
      this.store.deleteRecord(calling);
    }.bind(this));
  }
});

App.Calling = DS.Model.extend({
  userId: DS.attr('number')
});

App.User#callUpを実行するとApp.Callingモデルを作成し即座にsaveした後に削除を行います。

こうすることで、POST /callingsなXHRが飛ぶのでRESTfulなAPIでユーザーを呼び出すという動作を行えるようになります。

モデルのunit test

さてcallUpメソッドのテストは以下のように書きました(ember-mochaを使っています)

describeModel('uesr', 'User', {
  needs: [],
  beforeSetup: function() {}
}, function() {

  beforeEach(function() {
    this.model = this.subject();
  })

  describe(function() {
    beforeEach(function() {
      Ember.run(function() {
        this.fakePromise = { then: function(callback) { callback() } };
        this.fakeCalling = { save: function() { return this.fakePromise }.bind(this) };

        sinon.stub(this.model.store, 'createRecord')
          .withArgs('calling', { userId: 0 })
          .returns(this.fakeCalling);

        sinon.stub(this.model.store, 'deleteRecord')
          .withArgs(this.fakeCalling);

        this.model.set('id', 0)
      }.bind(this))
    })

    it('should create new calling and delete', function() {
      Ember.run(function() {
        this.model.callUp();
        expect(this.model.store.createRecord.called).to.be.ok
        expect(this.model.store.deleteRecord.called).to.be.ok
      }.bind(this))
    })
  })

})

これでstoreオブジェクトを使ってApp.Callingをcreateしてsaveしてdelete...という流れがテストできるようになります。

this.model(this.subject()の戻り値)がundefined

しかしこの後に更に別のテストを追加するとthis.modelはundefinedになってしまいます。

なんでだぁぁぁぁぁぁああ、と思ってよくよくコードを見直すと

sinon.stub(this.model.store, 'createRecord')

この時点でstore.createRecordは使えない子になってるわけですよね。
しかも特定の引数の場合のみ戻り値を設定しているので、それ以外はundefinedが返るはずです。

this.subject()って中でstore.createRecordを呼び出しているんです。

テストの一番最初のbeforeEachでthis.modelにthis.subject()の戻り値をセットしなおしているので、callUpのテストの後は全てundefinedがthis.modelにセットされるようになるわけです。

sinon.stubしたらrestore

要は戻せばいいだけ

afterEach(function() {
  this.model.store.createRecord.restore();
  this.model.store.deleteRecord.restore();
})

ドキュメントに書いてあるよね
http://sinonjs.org/docs/#stubs

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2