Javascript 如何在NodeJS中测试递归调用的函数?
我有一个用ES6/7编写的循环函数,它是由babel传输的。我创建了一个循环函数,使用mongoose检查是否存在用户文档Javascript 如何在NodeJS中测试递归调用的函数?,javascript,node.js,testing,recursion,mocha.js,Javascript,Node.js,Testing,Recursion,Mocha.js,我有一个用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
// 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替换了delay方法,将其替换为只返回值的自定义延迟函数。此时,我可以将代码更改为如下所示:
// 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
}
}
问题是源代码正在被修改以适应测试。有更好、更干净的解决方案吗 我不确定您为什么要使用递归解决方案而不是迭代解决方案,但如果没有其他原因,您可能更容易以迭代方式编写它,这样就不会破坏堆栈:
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);
还没有通过解释器测试或运行它-但是你明白了
然后在测试模式中,只需提供一个测试用户。因为您可能需要编写使用用户引用的测试。有几个库可用于测试与时间相关的事件。据我所知,最常见的解决方案是Lolex-,Sinon项目的早期部分。Lolex的问题是,它同步转发计时器,从而忽略诸如本机节点承诺或
进程.nextTick
之类的事件(尽管它确实正确地伪造了setImmediate
),因此您可能会遇到一些棘手的问题。请注意外部库-例如,bluebird
缓存初始的setImmediate
,因此您需要手动处理它
另一个选择是Zurvan(免责声明:我写的)。它比Lolex更难处理,因为它大量使用承诺,但在存在微队列任务(process.nextTick
,nativePromise
)时行为正常,并且有一个内置的bluebird兼容性选项
这两个库都允许您根据任意长度终止与时间相关的事件,并覆盖
Date
实例(zurvan还覆盖process.uptime
和process.hrtime
)。如果在测试中执行实际的异步IO,则两者都不安全。我在这里编写了一个示例,说明如何测试递归调用的函数:
此测试使用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,但相同的测试前提将适用于您的完整方法。另外请注意,您还需要对延迟方法进行存根。谢谢您的回答。但是如果我在测试这个,我如何测试在没有用户存在的情况下触发的条件分支呢。如果我使用的是Mocha,测试最终将超时,因为它将继续调用自身。然后在运行测试之前显式取消用户设置,然后开始运行测试,稍等片刻,然后设置用户。谢谢Stephan,这就是我的想法。如果延迟时间过长(5分钟-1小时),该怎么办。有一种及时“向前跳”的Sinon helper方法,不是吗?五年过去了,没有一个答案被标记为被接受。有人帮过你吗?