使用 Promises 和 Spies 进行单元测试
Unit Testing with Promises and Spies
我有以下文件:-
target.js
var target = function(repository, logger) {
return {
addTarget : function(target) {
repository.add(target).then(
function (newTarget) {
console.log("added");
logger.info("added");
},
function (err) {
console.log("error");
logger.info("error");
}
);
}
};
};
module.exports = target;
targetTest.js
var chai = require("chai"),
expect = chai.expect,
sinon = require("sinon"),
Promise = require("bluebird"),
baseTarget = require("../target");
describe("target", function(){
it("should log error when it occurs", function() {
var mockRepository = {
add : sinon.stub().returns(Promise.reject(new Error()))
};
var mockLogger = {
info : sinon.spy()
};
var target = baseTarget(mockRepository, mockLogger);
target.addTarget("target");
expect(mockLogger.info.calledWith("error")).to.be.true;
});
});
我遇到的问题是 expect(mockLogger.info.calledWith("error")).to.be.true;
returns false
因为存储库上的 add
方法是异步的,因此尚未执行。是否有正确执行此操作的模式。
这实际上是一个关于 'how Promises work' 的问题,而不是关于它们如何在测试框架内工作的问题 - 答案是它们的行为保持完全相同。
Is there a pattern for doing this properly.
与其说它是一种模式,不如说它是构建 Promises 的目的。 then
的每个成功处理程序在最后一个成功时按顺序执行。在您的代码中,我们可以 return 通过调用 repository#add
创建的 Promise,就像您想要使用它的结果或在 addTarget
之外执行一些外部依赖操作一样:
addTarget: function (target) {
return repository
// ^^^^^^
.add(target)
.then(function (newTarget) {
console.log("added");
logger.info("added");
}, function (err) {
console.log("error");
logger.info("error");
});
}
然后将您的期望放在 then
中,它将在 addTarget
:
中创建的 Promise 链的所有成员成功时执行
target.addTarget("target").then(function () {
expect(mockLogger.info.calledWith("error")).to.be.true;
cb();
});
异步测试
您会注意到在上面的示例中还有一个函数调用 cb
。由于您的测试是异步的,您需要在测试完成后 'tell' 测试框架。这通常是通过使用参数声明 it
函数来完成的,框架将从该参数推断测试是异步的并传入回调:
describe("target", function () {
it("should log error when it occurs", function (cb) {
// ^^^^
});
});
我有以下文件:-
target.js
var target = function(repository, logger) {
return {
addTarget : function(target) {
repository.add(target).then(
function (newTarget) {
console.log("added");
logger.info("added");
},
function (err) {
console.log("error");
logger.info("error");
}
);
}
};
};
module.exports = target;
targetTest.js
var chai = require("chai"),
expect = chai.expect,
sinon = require("sinon"),
Promise = require("bluebird"),
baseTarget = require("../target");
describe("target", function(){
it("should log error when it occurs", function() {
var mockRepository = {
add : sinon.stub().returns(Promise.reject(new Error()))
};
var mockLogger = {
info : sinon.spy()
};
var target = baseTarget(mockRepository, mockLogger);
target.addTarget("target");
expect(mockLogger.info.calledWith("error")).to.be.true;
});
});
我遇到的问题是 expect(mockLogger.info.calledWith("error")).to.be.true;
returns false
因为存储库上的 add
方法是异步的,因此尚未执行。是否有正确执行此操作的模式。
这实际上是一个关于 'how Promises work' 的问题,而不是关于它们如何在测试框架内工作的问题 - 答案是它们的行为保持完全相同。
Is there a pattern for doing this properly.
与其说它是一种模式,不如说它是构建 Promises 的目的。 then
的每个成功处理程序在最后一个成功时按顺序执行。在您的代码中,我们可以 return 通过调用 repository#add
创建的 Promise,就像您想要使用它的结果或在 addTarget
之外执行一些外部依赖操作一样:
addTarget: function (target) {
return repository
// ^^^^^^
.add(target)
.then(function (newTarget) {
console.log("added");
logger.info("added");
}, function (err) {
console.log("error");
logger.info("error");
});
}
然后将您的期望放在 then
中,它将在 addTarget
:
target.addTarget("target").then(function () {
expect(mockLogger.info.calledWith("error")).to.be.true;
cb();
});
异步测试
您会注意到在上面的示例中还有一个函数调用 cb
。由于您的测试是异步的,您需要在测试完成后 'tell' 测试框架。这通常是通过使用参数声明 it
函数来完成的,框架将从该参数推断测试是异步的并传入回调:
describe("target", function () {
it("should log error when it occurs", function (cb) {
// ^^^^
});
});