2017-03-07 51 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(); 
    }); 
    });