当相邻测试存在时,Mocha异步测试运行两次

时间:2014-10-01 19:51:07

标签: node.js mocha

这令人沮丧地令人费解。

我有以下测试夹具:

describe('#post', function(){
    var options,
        bodyContent,
        bodyWriter;

    beforeEach(function(){
        // setup common objects ...
    });

    it('should have request body', function(done){
        httpHelper.post(options, bodyWriter, function(err, data){
            should.not.exist(err);
            should.exist(requestData.body);
            requestData.body.should.eql(bodyContent);
            done();
        });
    });

    // ...
});

现在,这很好用 - 直到我添加另一个测试:

it('should contain path from options arg', function(done){
    httpHelper(options, bodyWriter, function(err, data){
        should.not.exist(err);
        requestData.options.path.should.eql(options.path);
        done();
    });
});

现在,当我运行灯具时,我得到以下内容:

http
    #post
      ✓ should require options
      ✓ should have body
      1) should have body
      ✓ should contain path from options arg

我不知道为什么这个测试会运行两次。有什么想法吗?

1 个答案:

答案 0 :(得分:1)

感谢@Louis的评论,我能够找出问题所在。我在测试模块中做的一件事就是伪造本机https模块并使用https://github.com/felixge/node-sandboxed-module注入它。问题出在我的假货上。

var fakeHttpsModule = (function(){
    var response = new EventEmitter(); 
    response.setEncoding = function(val){ /* no op */ };

    var request = function(options, callback) { 
        requestData.options = options;

        callback(response);
        return {
            write: function(value){
                requestData.body += value;
                response.emit('data', value);
            },
            end: function(){
                response.emit('end');
            },
            on: function(event, callback){ /* no op */ }
        };
    };

    return {
        request: request
    };
})();

问题基于response对象的范围。通过将其作用于模块,每次测试称为request方法时,该测试的回调最终会被添加为EventEmitter的注册。因此,调用此方法的第一个测试之后的每个测试都会得到Done()被调用多次的错误。

解决方案是简单地移动response的声明,使其范围限定为request函数,如下所示。

var fakeHttpsModule = (function(){      
    var request = function(options, callback) { 
        requestData.options = options;

        var response = new EventEmitter(); 
        response.setEncoding = function(val){ /* no op */ };

        callback(response);
        return {
            write: function(value){
                requestData.body += value;
                response.emit('data', value);
            },
            end: function(){
                response.emit('end');
            },
            on: function(event, callback){ /* no op */ }
        };
    };

    return {
        request: request
    };
})();