【问题标题】:How do you assert when testing a Node module that uses promises?在测试使用 Promise 的 Node 模块时如何断言?
【发布时间】:2015-03-28 23:36:36
【问题描述】:

我有一个节点控制器“simpleController”,它依赖于“DataAccess”的一个实例。控制器在“DataAccess”实例上调用函数“getData”并返回一个promise。如果 promise 然后被拒绝,控制器应该返回 500 的状态。

我想在“simpleController”上编写一个测试,但要模拟“DataAccess”的实例,这样我就可以返回一个失败的承诺并断言“simpleController”的行为符合预期。

我试图编写一个单元测试来执行此操作,但测试超时。

(function (simpleController) {

    var DataAccess = require('./DataAccess');

    var dataAccessInstance;

    simpleController.init = function (dataSource) {
        dataAccessInstance = new DataAccess(dataSource);
    };

    simpleController.setMockDependencies = function (mockDataAccessInstance) {
        dataAccessInstance = mockDataAccessInstance;
    };

    simpleController.performAction = function (req, res) {

        var entityId = req.query.id;

        dataAccessInstance.getData(entityId)
            .then(function (data){
                res.status(200).json(data);
            },
            function (err) {
                res.status(200).json(err);
            });
    }

})(module.exports);



/* global describe, it */
'use strict';

var assert = require('assert');
var sinon = require('sinon');
var Q = require('q');
var DataAccess = require('../lib/temp/DataAccess');

describe('Simple Controller Tests', function () {

    var simpleController;
    var dataAccess;

    beforeEach(function (done) {

        simpleController = require('../lib/temp/simpleController');

        var dataSource = 'dummy';
        dataAccess = new DataAccess(dataSource);

        done();
    });


    it('should return status of 500 if data access fails', function (done) {

        // Arrange
        var req = { query: { id: '12345678' } };
        var res = {};

        var deferred = Q.defer();

        var stub = sinon.stub(dataAccess, 'getData', function() {
            return deferred.promise;
        });

        simpleController.setMockDependencies(dataAccess);

        deferred.promise.fail(function () {

            // Assert
            assert.ok(stub.called);
            assert.equal(res.status, 500);

            done();

        });

        // Act
        simpleController.performAction(req, res);

        deferred.reject();
    });

});



(function () {

    function DataAccess(dataSource) {
        this.dataSource = dataSource;
    }

    DataAccess.prototype.getData = function (entityId) {
        throw new Error('Not implemented');
    };

    module.exports = DataAccess;
})();

任何帮助将不胜感激。

【问题讨论】:

    标签: javascript node.js mocha.js q sinon


    【解决方案1】:

    据我所知,您遇到的问题是您在两个地方为您的承诺提供了失败处理程序。一次通过在您的测试中调用 deferred.promise.fail ,一次通过将第二个参数传递给 dataAccessInstance.getData(entityId).then 在您的控制器中。您的控制器中的那个可能正在替换您在测试中添加的那个。我建议删除此代码(它并没有真正做任何有用的事情):

    deferred.promise.fail(function () {
    
            // Assert
            assert.ok(stub.called);
            assert.equal(res.status, 500);
    
            done();
    
        });
    

    而不是在你的测试中使用一个空对象作为 res ,添加一个状态方法,并在那里做你的断言:

    it('should return status of 500 if data access fails', function (done) {
    
        // Arrange
        var req = { query: { id: '12345678' } };
        var res = {};
    
        var deferred = Q.defer();
    
        var stub = sinon.stub(dataAccess, 'getData', function() {
            return deferred.promise;
        });
    
        simpleController.setMockDependencies(dataAccess);
    
        res.status = function (status) {
    
            // Assert
            assert.ok(stub.called);
            assert.equal(status, 500);
    
            done();
    
        };
    
        // Act
        simpleController.performAction(req, res);
    
        deferred.reject();
    });
    

    另外,请注意,在您的控制器中,您使用 200 表示成功和失败,我认为您的意思是使用 500 表示失败。最后,您应该在 Promise 链的末尾添加 .done():

    dataAccessInstance.getData(entityId)
           .then(function (data){
               res.status(200).json(data);
           },
           function (err) {
               res.status(500).json(err);
           })
           .done();
    

    (请参阅http://documentup.com/kriskowal/q/#tutorial/the-end)。如果您的测试失败,这将避免超时。

    【讨论】:

    • 不,fail 处理程序不会相互替换。
    • 对于问题的原因,我对我的 cmets 进行了纠正。在原始代码中,尝试在未定义 res 方法的 res 对象上调用 res.status()。承诺链末尾缺少 .done() 掩盖了这个问题,因为它导致了超时。添加 .done() 后,我们会看到:TypeError: Object # has no method 'status'
    猜你喜欢
    • 1970-01-01
    • 2019-06-19
    • 2017-02-24
    • 1970-01-01
    • 2020-02-11
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多