2014-10-01 92 views
0

这是令人沮丧的令人沮丧的。当存在相邻测试时,摩卡异步测试运行两次

我有以下的测试夹具:

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

如果''done'提供''应该有body''(或'should have body'' ???)测试会被调用两次,测试看起来会运行两次。如果你传递给'httpHelper'的回调在某处被注册了,并且这个注册在测试之间仍然存在,那么当你的第二个测试执行时,第一个和第二个测试中的回调将被执行。 – Louis 2014-10-01 23:18:36

+0

这个线索完全帮助我发现问题。将张贴导致问题的代码。 – 2014-10-01 23:41:18

回答

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 
    }; 
})();