5
 onSaveEvent: function (event) {
                if (this.model !== null) {
                    var that = this;

                    this.model.save(this.model.toJSON(), {
                        success: function (model) {
                            that.model = model;
                            that.model.attributes.isDirty = false;
                        },

                        error: function (model, xhr) {
                            that.model.attributes.isDirty = true;
                        }
                    });
                }
            }
        }

如何在 Jasmine 中对模型的保存成功和错误响应进行单元测试?

4

4 回答 4

2

要在没有假服务器的情况下进行测试,您可以测试该函数是否已绑定到模型,然后自己调用绑定的函数。换句话说,从模型中模拟出 ajax 保存部分。

var view = new YourView()
jasmine.spyOne(view.model, 'save')
view. onSaveEvent()
var args = view.model.save.mostRecentCall.args

args[1].success()
expect(view.model.attributes.isDirty).toBeFalsy()

args[1].error()
expect(view.model.attributes.isDirty). toBeTruthy()
于 2013-05-06T06:57:25.100 回答
1

您可以使用 Sinon.js 为您的测试创建一个假服务器。

http://sinonjs.org/

示例代码:

  describe("when saving a user model", function() {

    beforeEach(function() {
      this.server = sinon.fakeServer.create();
      this.responseBody = '{"name":"test user","id":1,"title":"tester"}';
      this.server.respondWith(
        "POST",
        "/user",
        [
          200,
          {"Content-Type": "application/json"},
          this.responseBody
        ]
      );
      this.eventSpy = sinon.spy();
    });

    afterEach(function() {
      this.server.restore();
    });

    it("should not save when name is blank", function() {
      this.user.bind("error", this.eventSpy);
      this.user.save({"name": ""});

      expect(this.eventSpy).toHaveBeenCalledOnce();    
      expect(this.eventSpy).toHaveBeenCalledWith(this.user, "cannot have a blank name");
    });

    it("should call the server", function() {
      this.user.save();
      expect(this.server.requests[0].method).toEqual("POST");
      expect(this.server.requests[0].url).toEqual("/user");
      expect(JSON.parse(this.server.requests[0].requestBody)).toEqual(this.user.attributes);
    });

  });
于 2013-05-06T00:17:28.733 回答
0

您需要 sinon 来模拟服务器响应。这个库有这样的实用程序:

 this.server.respondWith("GET", "/episode/123",
      [200, {"Content-Type": "application/json"},
      '{"id":123,"title":"Hollywood - Part 2"}']);

因此,只要您有一个具有根情节和 id 123 的模型,sinon 就会在 fetch 调用中返回它。

阅读: http ://tinnedfruit.com/2011/03/03/testing-backbone-apps-with-jasmine-sinon.html

更新:作为询问者请求添加第二个解决方法。模拟保存方法。

//在你的测试中使用它而不是 Backbone.js 模型

var ExtendedModel = Backbone.Model.extend({
    //mocked save:
    save : function(data, options){
         if( data ){
             this.set(data);
         }
         var mocked = this.toJSON();
         if( !mocked.id ){
             mocked.id = new Date().getTime();
         } 
         mocked = this.parse(mocked);
         if( options.success ){
             options.success(this);  
         } 
         if( options.error ){
             options.error(this);  
         } 
    }
});

var MyModel = ExtendedModel.extend({
});

但是我仍然建议您使用Sinon。模拟 Backbone.js 并不优雅,并且还支持标头响应代码和其他内容也更复杂,并且是一种重新发明轮子。使用 sinon 时,您只需向库添加创建服务器响应。

于 2013-05-06T00:18:00.940 回答
0

我不确定我是否喜欢在这里通过 sinon,毕竟 ajax 调用是由主干进行的,而不是由您正在测试的单元进行的,这是我的解决方案

    var Model = Backbone.Model.extend({
      success_callback : function (model){
        this.model = model;
        this.model.attributes.isDirty = false;

      },
      error_callback: function (model, xhr){

      },
      onSaveEvent: function (event) {

        this.save([], {
            success: _.bind(this.save_success, this),
            error: _.bind(this.error_callback, this);
        });
    });


    var callback_invoker = function(type_str, which_argument) {
      this.which_argument = which_argument || 0;
      this.type_str = type_str;
      var func = function() {
        var options = arguments[this.which_argument] || {};
        if (this.type_str == 'success') {
          var run = options.success || function() {};

        }else if (this.type_str == 'error') {
          var run = options.error || function() {};
        }
        run();
      };
      this.function = _.bind(func, this);
    };

    it('save success calls callback', function() {
      instance = new Model();
      spyOn(instance, 'save_success');
      spyOn(_,'bind').andCallThrough();
      var invoker = new callback_invoker('success', 1);
      spyOn(instance, 'save').andCallFake(invoker.function);
      instance.onSaveEvent();
      expect(_.bind).toHaveBeenCalledWith(instance.save_success, instance);
      expect(instance.save_success).toHaveBeenCalled();
    });
于 2014-01-24T11:34:11.137 回答