在测试使用承诺的 Node 模块时,您如何断言

How do you assert when testing a Node module that uses promises?

本文关键字:何断言 断言 测试 承诺 模块 Node      更新时间:2023-09-26

我有一个节点控制器"simpleController",它依赖于"DataAccess"的实例。控制器在"DataAccess"实例上调用函数"getData",并向其返回一个承诺。如果承诺随后被拒绝,则控制器应返回状态 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;
})();

任何协助将不胜感激。

据我所知,您遇到的问题是您在两个地方为您的承诺提供了失败处理程序。一次是在测试中调用 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 表示失败。最后,你应该在承诺链的末尾添加 .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)。这将避免在测试失败时超时。