我有一个用ES6 / 7编写的循环函数,由babel编译。我创建了一个定期函数,使用mongoose检查是否有用户文档。
// Keep checking if there is a user, if there is let execution continue
export async function checkIfUserExists(){
let user = await User.findOneAsync({});
// if there is no user delay one minute and check again
if(user === null){
await delay(1000 * 60 * 1)
return checkIfUserExists()
} else {
// otherwise, if there a user, let the execution move on
return true
}
}
如果没有用户,我使用delay
库来延迟执行一分钟,递归调用该函数。
这允许暂停执行整个功能,直到找到用户:
async function overallFunction(){
await checkIfUserExists()
// more logic
}
else分支很容易生成测试。如何为验证递归正常工作的if分支创建测试?
目前我已经在测试期间用proxyquire替换了延迟方法,将其替换为只返回值的自定义延迟函数。此时我可以将代码更改为:
// Keep checking if there is a user, if there is let execution continue
export async function checkIfUserExists(){
let user = await User.findOneAsync({});
// if there is no user delay one minute and check again
if(user === null){
let testing = await delay(1000 * 60 * 1)
if (testing) return false
return checkIfUserExists()
} else {
// otherwise, if there a user, let the execution move on
return
}
}
问题是源代码正在被更改以适应测试。有更好,更清洁的解决方案吗?
答案 0 :(得分:1)
我不确定你为什么要使用递归解决方案而不是迭代解决方案 - 但是如果没有其他原因可以更容易迭代地编写它,那么你就不会破坏堆栈:
do{
let user = await User.findOneAsync({});
// if there is no user delay one minute and check again
if(user === null){
await delay(1000 * 60 * 1);
}
else{
return true;
}
}while (!user);
没有通过翻译测试或运行 - 但你明白了。
然后在您的测试模式下 - 只提供测试用户。因为您可能需要编写使用对用户的引用的测试。
答案 1 :(得分:1)
有几个库可用于测试与时间相关的事件。据我所知,最常见的解决方案是Lolex - https://github.com/sinonjs/lolex,是Sinon项目的早期部分。 Lolex的问题在于它同步转发定时器,因此忽略了诸如本机节点承诺或process.nextTick
之类的事件(虽然它确实假冒setImmediate
) - 因此你可能会遇到一些令人讨厌的问题。注意外部库 - 例如,bluebird
缓存初始setImmediate
,因此您需要以某种方式手动处理它。
另一个选择是Zurvan - https://github.com/Lewerow/zurvan(免责声明:我写了它)。它比Lolex更难解决,因为它大量使用promises,但在存在微队任务(process.nextTick
,native Promise
)时表现正常,并且有蓝鸟的内置兼容性选项。
这两个库都允许您使用arbirary长度过期与时间相关的事件,并覆盖Date
个实例(zurvan也会覆盖process.uptime
和process.hrtime
。如果在测试中执行实际的异步IO,则它们都不安全。
答案 2 :(得分:1)
我已经写了一个例子,说明如何在这里测试你的递归调用函数:
https://jsfiddle.net/Fresh/qppprz20/
此测试使用Sinon javascript测试库。您可以在第n次调用时设置存根的行为,因此您可以模拟何时不返回用户,然后在返回用户时进行模拟,例如
// Stub the method behaviour using Sinon javascript framework
var user = new User();
var userStub = sinon.stub(user, 'findOneAsync');
userStub.onFirstCall().returns(null);
userStub.onSecondCall().returns({});
因此onFirstCall模拟第一次调用,onSecondCall模拟递归调用。
请注意,在完整示例中,我简化了checkIfUserExists,但相同的测试前提将适用于您的完整方法。另请注意,您还需要存根延迟方法。