【问题标题】:Testing results of an initial ajax request with Jasmine 2.0使用 Jasmine 2.0 测试初始 ajax 请求的结果
【发布时间】:2014-03-05 21:35:01
【问题描述】:

我正在使用 Jasmine 2.0 测试主干视图。视图在加载时发出初始 ajax 请求,以用值填充其表单字段。我希望我的 Jasmine 测试(在下面的 it 函数中)仅在收到这些值后运行。

测试当前失败,因为似乎在测试运行后收到了 ajax 请求,即使我正在存根 ajax 请求。

我应该如何编写这个测试?

describe('View', function() {

  var formFieldValues = [/* blah */];
  var view;

  beforeEach(function(done) {
    jasmine.Ajax.install();
    jasmine.Ajax.stubRequest('/form-fields').andReturn({
      responseJSON: formFieldValues
    });
    view = new View({el: $('<main></main>')}); // makes ajax call on initialization
    $('body').append(view.el);
  });

  afterEach(function() {
    view.remove();
    jasmine.Ajax.uninstall();
  });

  it('form fields have values', function(done) {
    // PROBLEM IS HERE: THE FOLLOWING RUNS BEFORE VIEW'S AJAX CALL FINISHES
    expect(view.$('[name="fieldName"]').children().length).toEqual(formFieldValues.length);
  });

});

【问题讨论】:

    标签: javascript backbone.js jasmine backbone-views jasmine-jquery


    【解决方案1】:

    看起来您实际上并没有运行异步规范。我注意到您的 beforeEachit 都收到了 done 回调,但他们都没有调用。如果你正在使用 ajax,那么你可能不需要运行异步规范,因为 stub 会 有效地使ajax请求同步。

    当我运行以下代码时,一切正常。

    规格:

    describe('View', function() {
    
      var formFieldValues = [{name: 'foo'}, {name: 'bar'}];
      var view;
    
      beforeEach(function() {
        jasmine.Ajax.install();
        jasmine.Ajax.stubRequest('/form-fields').andReturn({
          responseText: JSON.stringify(formFieldValues)
        });
        view = new View(); // makes ajax call on initialization
      });
    
      afterEach(function() {
        jasmine.Ajax.uninstall();
      });
    
      it('form fields have values', function() {
        // PROBLEM IS HERE: THE FOLLOWING RUNS BEFORE VIEW'S AJAX CALL FINISHES
        expect(view.$('[name="fieldName"]').children().length).toEqual(formFieldValues.length);
      });
    
    });
    

    我的虚拟实现:

    Collection = Backbone.Collection.extend({
      url: '/form-fields'
    });
    
    View = Backbone.View.extend({
      initialize: function() {
        this.collection = new Collection();
        this.collection.on('reset', this.render, this);
        this.collection.fetch({reset: true});
      },
    
      render: function() {
        var innerEl = $('<div name="fieldName"></div>')
        this.collection.each(function(item) {
          innerEl.append('<span></span>');
        });
        this.$el.append(innerEl);
      }
    });
    

    【讨论】:

    • 你的代码确实有效,它帮助我解决了我自己的问题,所以我可能会奖励你积分。但是我仍然有一个奇怪的问题:我触发了一个“更改”事件,它最初实际上设置了字段值,但是我在调​​试器中看到 Backbone 的“delegateEvents”在我的更改被触发后运行,这似乎是根问题。这不会发生在现场,而只会发生在 Jasmine 测试中。
    • Backbone 在构造函数的最后调用delegateEvents,如果你让自己陷入某种回调的疯狂小镇,并且在视图仍在构建自身时触发了你的更改事件,这可能会发生。如果不了解更改事件的外观和运行位置,则很难帮助调试它。
    【解决方案2】:

    应该使用 runs() 和 waitFor() 方法 使其异步。 对 run() 方法的调用充当单独的测试块,其中最后一个将进行异步调用。在最简单的情况下,可以使用 setTimeout() 来模拟异步行为。在更复杂的用法中,会进行实际调用,例如对启用 Ajax 的对象。

    waitsFor() 方法接受三个参数:“latch”函数、失败消息、超时(以毫秒为单位)

    runs(function() {
        flag = false;
        value = 0;
    
    setTimeout(function() {
      value++;
      //keep returning false…
      flag = false;
    }, 500);
      });
    
      waitsFor(function() {
        return flag;
      }, "The Value should be incremented", 5000);
    });
    

    或者你可以试试 发出真正的 Ajax 请求

    当需要执行集成测试时,您可能希望执行真正的 Ajax 调用,而不仅仅是模仿它们。没问题。只需创建一个间谍,进行 Ajax 调用,然后是 waitsFor(),您可以在其中检查 callback.callCount 属性或你有什么: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

    it("should make a real AJAX request", function () {
        var callback = jasmine.createSpy();
        makeAjaxCall(callback);
        waitsFor(function() {
            return callback.callCount > 0;
        }, "The Ajax call timed out.", 5000);
    
        runs(function() {
            expect(callback).toHaveBeenCalled();
        });
    });
    
    function makeAjaxCall(callback) {
        $.ajax({
            type: "GET",
            url: "data.json",
            contentType: "application/json; charset=utf-8"
            dataType: "json",
            success: callback
        });
    }
    

    【讨论】:

    • "runs" 和 "waitsFor" 似乎是 Jasmine 2.0 之前的一部分。
    • 那我觉得Jasmine 2.0应该也有类似的东西。
    • Jasmine 2.0 引入了一个done 回调,以防你真的需要一个真正异步的规范。在发出 ajax 请求的情况下,通过模拟 ajax 调用并让它在测试中同步返回,您将获得更一致(更快)的结果。
    猜你喜欢
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 2016-06-03
    • 1970-01-01
    • 2015-09-21
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    相关资源
    最近更新 更多