2014-10-01 96 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 
    }; 
})();