Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/visual-studio-2010/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Sinon.stub()每次返回不同的值';这叫什么_Javascript_Node.js_Mocha.js_Sinon - Fatal编程技术网

Javascript Sinon.stub()每次返回不同的值';这叫什么

Javascript Sinon.stub()每次返回不同的值';这叫什么,javascript,node.js,mocha.js,sinon,Javascript,Node.js,Mocha.js,Sinon,以下是我编写测试的代码: 'use strict'; var internals = {}; var _ = require('lodash'); module.exports = { initialize: function (query) { internals.query = query; }, createField: function (fieldId, accountId, payload) { function ca

以下是我编写测试的代码:

'use strict';

var internals = {};

var _ = require('lodash');

module.exports = {
    initialize: function (query) {
        internals.query = query;
    },

    createField: function (fieldId, accountId, payload) {

        function callQuery (parList) {
            var query = 'INSERT into fields VALUES (:uuid, :accountId, :shortcutName, :displayName, :fieldType, :widgetType, :columnOrder, :options, :required, NULL)';
            return internals.query(query, parList, function () { return fieldId; });
        }

        var increment = 10;
        var parameterList = {
            'uuid': fieldId,
            'accountId': accountId,
            'shortcutName': payload.shortcutName,
            'displayName': payload.displayName,
            'fieldType': payload.fieldType,
            'widgetType': payload.widgetType,
            'columnOrder': payload.columnOrder,
            'options': JSON.stringify(payload.options) || null,
            'required': payload.required || 'f'
        };
        if (!payload.columnOrder) {
            var columnQuery = 'SELECT MAX(column_order) from fields';
            return internals.query(columnQuery, {}, function (x) {return x; })
                .then(function (results) {
                    var highestColumnOrder = results[0]['MAX(column_order)'];
                    var newHighestColumnOrder = Math.ceil(highestColumnOrder / 10) * 10;
                    if (newHighestColumnOrder > highestColumnOrder) {
                        parameterList.columnOrder = newHighestColumnOrder;
                    } else {
                        parameterList.columnOrder = newHighestColumnOrder + increment;
                    }
                    return callQuery(parameterList);
                });
        } else {
            return callQuery(parameterList);
        }
    },

    getFieldsByAccountId: function(accountId, showDeleted) {
        var callQuery = function(paramList) {
            var query = 'SELECT ' + paramList.columns.join(", ") + ' FROM fields WHERE account_id = :account_id';

            if (!showDeleted) {
                query +=  ' AND archived_at IS NULL';
            }

            return internals.query(query, paramList, function(rows) {
                return _.each(rows, function(row) {
                    if(row.options) {
                        row.options = JSON.parse(row.options);
                    }
                    row.required = !!row.required;
                });
            });
        };

        var columnList = ["uuid", "account_id", "shortcut_name", "display_name", "field_type", "required", "column_order", "options"];
        var paramList = {'account_id': accountId};

        if (showDeleted) {
            columnList.push("archived_at");
        }

        _.extend(paramList, {'columns': columnList});

        return callQuery(paramList);
    }
};
这是我的测试:

        'use strict';

var assert = require('assert');
var sinon = require('sinon');
var Promise = require('bluebird');
var proxyquire = require('proxyquire');

var returnedValues = require('../../../return_values.js');
var fieldGateway = proxyquire('../../../../src/fields/lib/gateway', {});

describe('gateway', function () {
    var accountId = 100;
    var fieldId = 200;
    var _query, sql, mockData, rows;

    describe('createField', function() {
        describe('is successful with a column order value', function () {

            beforeEach(function() {
                sql = 'INSERT into fields VALUES (:uuid, :accountId, :shortcutName, :displayName, :fieldType, :widgetType, :columnOrder, :options, :required, NULL)';
                mockData = returnedValues.getFieldInputValues();
            });

            it("should only insert new field", function () {
                _query = sinon.spy(function() { return Promise.resolve(); });
                fieldGateway.initialize(_query);
                fieldGateway.createField(fieldId, accountId, mockData);

                mockData.accountId = accountId;
                mockData.uuid = fieldId;
                mockData.options = JSON.stringify(mockData.options);
                assert.equal(sql, _query.getCall(0).args[0]);
                assert.deepEqual(mockData, _query.getCall(0).args[1]);
            });

            it.only("_query should be called with the right sql statement and parameterList", function () {
                _query = sinon.stub().returns(Promise.resolve(fieldId));
                // _query.onCall(0).returns(Promise.resolve([{'MAX(column_order)': 10}]));
                // _query.onCall(1).returns(Promise.resolve(fieldId));
                fieldGateway.initialize(_query);
                delete mockData.columnOrder;

                fieldGateway.createField(fieldId, accountId, mockData);
                console.log(_query.args);
                assert.equal(sql, _query.getCall(0).args[0]);

                fieldGateway.createField.restore();
            });
        });
    });

});

问题是,当测试运行时,唯一运行的SQL查询是
SELECT
语句。应该运行一条SQL语句,然后运行一条INSERT语句,这是因为
bluebird
是一个真正的Promise/a+兼容库。根据定义,所有链接承诺必须在不同的执行周期中运行。因此,只有第一个承诺是同步执行的(在相同的勾号中)

你应该告诉摩卡“等待”其他人采取行动。您可以通过在单元测试中指定一个
done
回调来实现这一点,并在承诺完成工作时相应地调用它

 it.only("_query should be called with the right sql statement and parameterList", function (done) {
    _query = sinon.stub().returns(Promise.resolve(fieldId));
    fieldGateway.initialize(_query);
    delete mockData.columnOrder;
    fieldGateway.createField(fieldId, accountId, mockData)
    .then(function(){
           /// assertion code should be adjusted here
         console.log(_query.args);
         assert.equal(sql, _query.getCall(0).args[0]);
         fieldGateway.createField.restore();
         //tell Mocha we're done, it can stop waiting
         done();
    })
    .catch(function(error) { 
      //in case promise chain was rejected unexpectedly
      //gracefully fail the test
         done(error); 
    };
});

每当您测试承诺返回函数时,您应该始终在
中处理结果。那么

第一个代码块应该是另一个函数的一部分吗?第二个
return
语句不属于函数。我假设测试中的
mockData
对象在每个
之前的
或类似的地方?@kevin628更新了测试以包括整个测试文件谢谢!!我必须移动
done()
之外调用,然后
,但它正在工作!!!我花了整整一天的时间试图理解这一点。非常感谢。嗯,你确定有一个承诺没有兑现吗?如果在调用承诺返回函数之后调用
done()
,则在链完全执行之前执行该函数。也许在您的情况下,您应该添加
.catch(function(error){done(error);}
,当承诺链被拒绝时,它将优雅地通过测试。但保留
done()
可测试承诺链的外部是逻辑错误,不管怎样,我有一个语法错误。它在
然后
语句中工作!是的,我也开始彻底检查你的代码。关于链接承诺,你都是正确的。它应该工作!但是我不明白你为什么调用
restore()
fieldGateway.createField
上的
。它不是间谍,是您目前正在测试的真实方法。我想它应该抛出,因为
restore
没有定义此方法,这是因为我最初删除了该方法。只是忘记了删除它