如何使用jasmine对保存的主干成功和错误响应进行单元测试

时间:2013-05-05 07:29:20

标签: jquery backbone.js jasmine jasmine-jquery jasmine-node

 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 个答案:

答案 0 :(得分: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()

答案 1 :(得分: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);
    });

  });

答案 2 :(得分:0)

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

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

因此,只要你有一个带有根剧集和id 123的模型,sinon就会在提取调用中返回它。

阅读本文: 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时,您只需要为库添加一个创建服务器响应。

答案 3 :(得分: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();
    });