如何使用 jasmine 测试完成和失败的延迟对象

2022-01-11 00:00:00 post jasmine jquery javascript

这里是关于 javascript 提交请求的代码 (1).
下面是关于使用jasmine模拟ajax请求的测试(2).

Here is the code about the javascript submit request (1).
Here is the test about mocking the ajax request by using jasmine (2).

我想模拟服务器行为.有什么想法吗?
有关详细信息,请参阅 (1) 和 (2) 中的注释.

I would like to mock the server behaviour. Any ideas?
See the comment in (1) and (2) for more details.

附:
实际上在这两种情况下,fakeFunction 的 done 和 fail 延迟对象都会被调用.

P.S.:
Actually in both case the done and the fail Deferred Object of fakeFunction are called.

(1)

submitForm: function () {
     // the server execute fail only if message.val() is empty
     // and I would like to mock this behaviour in (2)
     backendController.submitForm(message.val()).done(this.onSuccess).fail(this.onError);
},

backendController.submitForm = function (message) {
    return $.ajax({
        url: 'some url',
        type: 'POST',
        dataType: 'json',
        data: {
            message: message
        }
    }).done(function () {
        //some code;
    });
};

<小时>

(2)

describe('When Submit button handler fired', function () {
    var submitFormSpy,
        fakeFunction = function () {
            this.done = function () {
                return this;
            };
            this.fail = function () {
                return this;
            };
            return this;
        };

    beforeEach(function () {
        submitFormSpy = spyOn(backendController, 'submitForm').andCallFake(fakeFunction);
    });

    describe('if the message is empty', function () {
        beforeEach(function () {
            this.view.$el.find('#message').text('');
            this.view.$el.find('form').submit();
        });
        it('backendController.submitForm and fail Deferred Object should be called', function () {
            expect(submitFormSpy).toHaveBeenCalled();
            // how should I test that fail Deferred Object is called?
        });
    });

    describe('if the message is not empty', function () {
        beforeEach(function () {
            this.view.$el.find('#message').text('some text');
            this.view.$el.find('form').submit();
        });
        it('backendController.submitForm should be called and the fail Deferred Object should be not called', function () {
            expect(submitFormSpy).toHaveBeenCalled();
            // how should I test that fail Deferred Object is not called?
        });
    });

});

推荐答案

我们实际上遇到了同样的问题,试图测试代表 AJAXed 模板脚本的延迟对象以进行动态模板.我们的测试解决方案包括将 Jasmine-Ajax 库与 Jasmine 本身结合使用.

We actually ran into the same problem, trying to test Deferred objects that represent AJAXed template scripts for on-the-fly templating. Our testing solution involves using the Jasmine-Ajax library in conjunction with Jasmine itself.

所以可能会是这样的:

describe('When Submit button handler fired', function () {
  jasmine.Ajax.useMock();

  describe('if the message is empty', function () {

    beforeEach(function() {
      spyOn(backendController, 'submitForm').andCallThrough();
      // replace with wherever your callbacks are defined
      spyOn(this, 'onSuccess');
      spyOn(this, 'onFailure');
      this.view.$el.find('#message').text('');
      this.view.$el.find('form').submit();
    });

    it('backendController.submitForm and fail Deferred Object should be called', function () {
      expect(backendController.submitForm).toHaveBeenCalledWith('');
      mostRecentAjaxRequest().response({
        status: 500, // or whatever response code you want
        responseText: ''
      });

      expect( this.onSuccess ).not.toHaveBeenCalled();
      expect( this.onFailure ).toHaveBeenCalled();
    });
});

另一件事,如果可以的话,请尝试分解功能,这样您就不会在一次测试中测试整个 DOM-to-response-callback 路径.如果您足够细化,您实际上可以通过在测试中使用 Deferred 对象本身来测试异步 Deferred 解决方案!

Another thing, if you can, try to break up the functionality so you're not testing the entire DOM-to-response-callback path in one test. If you're granular enough, you can actually test asynchronous Deferred resolutions by using Deferred objects themselves inside your tests!

关键是在你的测试中实际使用 Deferred 对象,这样 expect 调用的范围仍然在你的 it 功能块内.

The key is to actually use Deferred objects within your tests themselves, so that the scope of the expect call is still within your it function block.

describe('loadTemplate', function() {
  it('passes back the response text', function() {
    jasmine.Ajax.mock();
    loadTemplate('template-request').done(function(response) {
      expect(response).toBe('foobar');
    });
    mostRecentAjaxRequest().response({ status:200, responseText:'foobar' });
  });
});

相关文章