2017-03-07 50 views
1

我有一個模塊,我輸出並有一個方法editHeroImage,我試圖使用mocha,chaisinon測試。模塊有兩個作爲參數傳遞的對象,connectionqueries。這些是mySql對象,其中一個包含與數據庫的連接,另一個包含在其單獨模塊中定義的查詢字符串。我正在導出並試圖測試的expObj是一個「幫手」模塊。nodejs - 測試失敗但回調被調用

我已經成功測試了此模塊的其他方法,與我試圖測試此方法的方式相同,但是,當我遇到由於某種原因而使用async模塊的方法時,我的測試不再按預期運行。我想知道在這種情況下我是否缺少了一些東西,因爲我測試了其他模塊和方法,它們也使用了async,但沒有遇到這種情況。

當我運行測試時,它記錄「你好!」如預期的那樣,但是稱爲callbackSpy的斷言失敗。

我在這裏失去了我的想法!請幫忙!到底是怎麼回事?試衣之間是否會有污染?被測

方法:

expObj.editHeroImage = function(connection, queries, postId, postData, callback) { 
    async.waterfall([ 
    function(next) { 
     var qString = queries.getSinglePostById(); 
     connection.query(qString, [postId], function(err, results) { 
     if (err) { 
      return next(err); 
     } 
     if (!results.length) { 
      console.log('NO POST FOUND WITH ID ' + postId); 
      return callback(); 
     } 
     next(null, results[0].hero_image); 
     }); 
    }, 
    function(heroImageId, next) { 
     if (!heroImageId) { 
     console.log('HERO IMAGE IS NEW - NEXT TICK!'); 
     return next(); 
     } 
     // Delete resized images of hero image 
     var queryStr = queries.deleteResizedImages(); 
     var resizedVals = [heroImageId]; 
     connection.query(queryStr, resizedVals, function(err) { 
     if (err) { 
      return callback(err); 
     } 
     console.log('DELETED RESIZED IMAGES OF HERO IMAGE ' + heroImageId); 
     var qString = queries.updateHeroImagePath(); 
     var values = [postData.hero_image, heroImageId]; 
     return connection.query(qString, values, function(err, results) { 
      if (err) { 
      return next(err); 
      } 
      console.log('UPDATED HERO IMAGE ' + heroImageId + ' WITH PATH ' + postData.hero_image); 
      next('break'); 
     }); 
     }); 
    }, 
    function addHeroImage(next) { 
     var qString = queries.insertImage(); 
     var values = [postData.hero_image, postId]; 
     connection.query(qString, values, function(err, results) { 
     if (err) { 
      return next(err); 
     } 
     next(null, results.insertId); 
     }); 
    }, 
    function addHeroImagePathToPost(heroImageId, next) { 
     var qString = queries.saveHeroImageId(); 
     var values = [heroImageId, postId]; 
     connection.query(qString, values, function(err) { 
     if (err) { 
      return next(err); 
     } 
     next(); 
     }); 
    } 
    ], function(err) { 
    if (err && err !== 'break') { 
     return callback(err); 
    } 
    console.log('HELLO!'); 
    callback(null); 
    }); 
}; 

測試,與設置:

'use strict'; 

var chai = require('chai'); 
var sinonChai = require("sinon-chai"); 
var proxyquire = require('proxyquire'); 
var sinon = require('sinon'); 
chai.use(sinonChai); 
var expect = chai.expect; 

describe('HELPERS', function() { 
    var testedModule, 
    callbackSpy, 
    fakeConnectionObj, 
    fakeQueriesObj, 
    fakePost, 
    fakeSnakeCaseObj, 
    queryStub, 
    connectionStub, 
    manageStub, 
    fakeCamelCaseObj; 

    beforeEach(function() { 
    fakePost = {}; 
    fakeConnectionObj = {}; 
    fakeQueriesObj = { 
     getPostIdFromImage: function() {}, 
     insertResizedImages: function() {}, 
     createPost: function() {}, 
     getPostImages: function() {}, 
     getPostsAlternativesImages: function() {}, 
     getSinglePostById: function() {}, 
     getAllImages: function() {}, 
     insertImage: function() {}, 
     deleteMainImage: function() {}, 
     deleteResizedImages: function() {}, 
     updateHeroImagePath: function() {}, 
     saveHeroImageId: function() {} 
    }; 

    afterEach(function() { 
     queryStub.resetBehavior(); 
    }); 
    fakeSnakeCaseObj = { 
     sub_title: '123', 
     hero_image: '456' 
    }; 
    fakeCamelCaseObj = { 
     subTitle: '123', 
     heroImage: '456' 
    }; 
    callbackSpy = sinon.spy(); 
    queryStub = sinon.stub(); 
    manageStub = sinon.stub(); 
    connectionStub = {query: queryStub}; 
    testedModule = proxyquire('./../../../../lib/modules/mySql/workers/helpers', { 
     './../../../factories/notification-service': { 
     select: function() { 
      return {manageSns: manageStub}; 
     } 
     } 
    }); 
    }); 

it('edits hero image', function() { 
    var _post = { 
     id: '123', 
     title: 'vf', 
     sub_title: 'vf', 
     slug: 'vf', 
     reading_time: 4, 
     created_at: '123', 
     published_at: '123', 
     deleted_on: false, 
     hero_image: 'hero_image_path' 
    }; 
    var _postId = '123'; 
    queryStub.onCall(0).callsArgWith(2, null, [{hero_image: '55'}]); 
    queryStub.onCall(1).callsArgWith(2, null); 
    queryStub.onCall(2).callsArgWith(2, null); 
    testedModule.editHeroImage(connectionStub, fakeQueriesObj, _postId, _post, function() { 
     console.log(arguments); // --> {'0': null} as expected 
     callbackSpy.apply(null, arguments); 
    }); 
    expect(callbackSpy).has.been.calledWith(null); 
    }); 
}); 

回答

1

你的說法可能是你的異步函數之前執行返回。

有很多方法可以確保您的異步函數完成執行。最乾淨的是格式化你的摩卡測試不同。

describe('...', function() { 
    var callbackSpy; 

    before(function() { 
     var _post = { 
      id: '123', 
      title: 'vf', 
      sub_title: 'vf', 
      slug: 'vf', 
      reading_time: 4, 
      created_at: '123', 
      published_at: '123', 
      deleted_on: false, 
      hero_image: 'hero_image_path' 
     }; 
     var _postId = '123'; 
     queryStub.onCall(0).callsArgWith(2, null, [{ 
      hero_image: '55' 
     }]); 
     queryStub.onCall(1).callsArgWith(2, null); 
     queryStub.onCall(2).callsArgWith(2, null); 

     return testedModule.editHeroImage(connectionStub, fakeQueriesObj, _postId, _post, function() { 
      console.log(arguments); // --> {'0': null} as expected 
      callbackSpy.apply(null, arguments); 
     }); 
    }); 

    it('edits hero image', function() { 
     expect(callbackSpy).has.been.calledWith(null); 
    }); 
}); 

注意,我已經包裹你的斷言在描述塊,所以我們可以使用before。您設置存根和執行類的實際邏輯已移至before塊並添加了一個返回,這可確保異步功能在完成之前完成斷言。

您的其他測試可能已通過,但它們也會受此影響,純粹是一個計時問題。

+0

事實上,你是正確的是它是一個時間問題。然而,使用您在斷言中包裝斷言的建議並使用before函數來設置測試會導致我的存根不再正常工作。然而,考慮到你對時間考慮的建議,我設法通過在我的測試套裝中使用'done'回調來解決問題。 – hyprstack

0

事實上@Varedis是正確的,因爲它是一個時間問題。然而,使用你的建議將斷言包裝在描述性的bloack中,並使用before函數來設置測試,導致我的存根不再正常工作。然而,考慮到您對時間考慮的建議,我設法通過在我的測試套裝中使用完成的回調來解決問題。通過保持設置我做了一個小小的改變,我的測試突然通過:

it('edits hero image', function(done) { 
    var _post = { 
     id: '123', 
     title: 'vf', 
     sub_title: 'vf', 
     slug: 'vf', 
     reading_time: 4, 
     created_at: '123', 
     published_at: '123', 
     deleted_on: false, 
     hero_image: 'hero_image_path' 
    }; 
    var _postId = '123'; 
    queryStub.onCall(0).callsArgWith(2, null, [{hero_image: '55'}]); 
    queryStub.onCall(1).callsArgWith(2, null); 
    queryStub.onCall(2).callsArgWith(2, null); 
    testedModule.editHeroImage(connectionStub, fakeQueriesObj, _postId, _post, function() { 
     callbackSpy.apply(null, arguments); 
     expect(callbackSpy).has.been.calledWith(null); 
     expect(callbackSpy).has.not.been.calledWith('FDgdjghg'); 
     done(); 
    }); 
    });