【问题标题】:Sinonjs fakeserver - multiple ajax callsSinonjs fakeserver - 多个 ajax 调用
【发布时间】:2015-04-02 23:25:49
【问题描述】:

我将 QUnit 与 sinon 一起使用。如何让 sinon 的 fakeserver 响应由相同方法调用的链式 ajax?

module('demo', {
    beforeEach: function(){
        this.server = sinon.fakeServer.create();
    },
    afterEach: function(){
        this.server.restore();
    }
});

test('chained ajax calls', function(assert){

    this.server.respondWith('GET', '/foo', [200, 
    { 'Content-Type': 'application/json' }, '{ "foo": 1 }' ]);

    this.server.respondWith('GET', '/bar', [200, 
    { 'Content-Type': 'application/json' }, '{ "bar": 1 }' ]);

    var successCount = 0;

    $.get('/foo', function(data){
        successCount++;
        $.get('/bar', function(){
            console.log('bar success');
            successCount++;
        });
    });

    this.server.respond();
    assert.strictEqual(successCount, 2);
});

我上面的问题是我只能从其中一种方法中得到响应。 fakeserver 能处理这个吗?

更新:似乎添加另一个server.respond() 可以解决问题。但一定有更好的办法吧?

根据文档,无论 ajax 调用次数如何,听起来都应该调用一次:

server.respond(); 使所有排队的异步请求都收到响应。

小提琴:http://jsfiddle.net/3qj20r5m/1/

【问题讨论】:

    标签: javascript ajax qunit sinon


    【解决方案1】:

    Sinon 文档指出autoRespond 不适合测试,因为它将异步执行。这默认为 10 毫秒后,这足以碰撞到下一个执行帧,可能会导致测试出现一些竞争条件。我发现这一点是因为我有类似的嵌套 AJAX 调用想要测试。

    我最终在fakeServer 上实现了一个respondImmediately 属性,它将同步响应任何请求。几周前它刚刚合并到项目中(v1.14.0),但如果你更新到最新版本,你应该能够得到它。 Check out the docs here..

    在您的beforeEach 块中,不要将autoRespond 属性设置为true,而是将respondImmediately 属性设置为true。然后删除所有server.respond() 调用,你应该设置!

    【讨论】:

    • 嗯,我刚刚测试过,它似乎不起作用。我错过了什么? jsfiddle.net/3qj20r5m/3
    • 啊,看起来这是一个 jQuery 主义,在回调上添加了 0ms setTimeout。这是使用原始 xhr 的嵌套案例:jsfiddle.net/3qj20r5m/5。使用 jQuery,你可能无法让你的测试异步:/
    • 我明白了。我目前为我的嵌套 jquery ajax 调用所做的是让服务器响应,只要有任何排队的调用等待。所以我想我会继续这样做。无论如何,非常感谢您添加的评论,希望它能帮助遇到类似问题的人......
    • @filur 我知道已经有一段时间了,但我找到了解决这个问题的方法。您可以使用respondImmediately 属性,然后也使用$.ajaxSetup 将所有ajax 请求默认为同步。当然,您不会想在 prod 中使用这些设置,但它可能会清理您的测试。这是你的原始小提琴,分叉并带有ajaxSetupjsfiddle.net/r9c44q5a
    • 谢谢。我认为您在示例中错过了$.ajaxSetup 吗?但这就是我今天要做的事情
    【解决方案2】:

    嗯,我认为server.repond() 也应该这样做。无论如何,我通常将我的假服务器设置为自动响应。除非您需要在响应之前检查请求,否则这似乎更容易:

    var server;
    QUnit.module('fake server tests', {
        beforeEach: function() {
            server = sinon.fakeServer.create();
    
            // *** it's this option I'm referring to...
            server.autoRespond = true;
    
            server.respondWith('GET', '/foo', [200, { 
                'Content-Type': 'application/json',
                '{ "foo": 1 }'  
            }]);
    
            server.respondWith('GET', '/bar', [200, { 
                'Content-Type': 'application/json',
                '{ "bar": 1 }'  
            }]);
        },
        afterEach: function() {
            server.restore();
        }
    });
    
    QUnit.test('do some ajax', function(assert) {
        var done = assert.async();
    
        doTwoAjaxCalls(function () {
    
            // whatever your assertions are...
            // (of course, your method would need to perform the callback...)
    
            done();
        });
    });
    

    更新

    查看您更新的代码,我们可以看到为什么您需要调用 respond() 两次:第一个响应调用从其队列中“释放”初始 ajax 请求(到 /foo),然后调用第一个成功回调.在该回调中,您启动了第二个 ajax 调用,Sinon 将一直保持到您再次调用 respond()

    换句话说,调用respond() 将使Sinon 释放所有当前持有的ajax 请求,但在你的情况下,一次只持有一个。使用我上面提到的autoRespond 选项可以消除这种需求,因为 Sinon 会立即“响应”,但我相信在这种情况下您需要使测试异步(或者至少,这是最佳实践)。

    祝你好运!

    【讨论】:

    • 哦,我以为假调用是同步执行的,所以我没有使用assert.async。有没有办法以同步方式执行调用?
    • 详细说明:在所有带有单个 ajax 调用的示例中,您似乎可以在不停止 QUIinit 的情况下等待响应(例如 kenpowers.net/blog/advanced-features-in-sinon "Make assertions, onces again, everything is synchronous.")。但是,对于像上面这样的嵌套调用,您似乎必须让 QUnit 等待。
    • 我更新了我的示例,使其更接近我的真实代码。调用实际上是嵌套的。也许这就是问题所在?
    • 如果您使用autoRespond 选项,则您的第二条评论大部分是正确的。在这种情况下,Sinon 将您的请求保存在假服务器中并等待您调用respond(),然后同步执行。但是,如果您使用autoRespond,我认为它将是异步的。
    • 哦,对你最后的评论:是的,调用的嵌套是不得不调用respond() 两次的问题。我会更新我的答案。
    猜你喜欢
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多