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
没有定义此方法,这是因为我最初删除了该方法。只是忘记了删除它