使用setTimeout测试IIFE

Testing IIFE with setTimeout

本文关键字:IIFE 测试 setTimeout 使用      更新时间:2023-09-26

测试用setTimeout:递归调用自己的IIFE(立即调用函数表达式)的最佳方法是什么

(function myFuncToBeTested() {
  // Code to be tested 
  ...
  setTimeout(myFuncToBeTested, timeout) // timeout should be checked
})()

我找到了以下解决方案,它用own存根替换了全局setTimeout函数。这有以下问题:

// Saving original setTimeout. This should be restored in test cleanup
originalSetTimeout = global.setTimeout
// Replace  with function
global.setTimeout = function setImmediate(myFunc, interval) {
   // FIXME: This function now always called
   // Save interval to be tested
   savedInterval = interval
}

这个函数可以变成一个对象吗?

var myObject = (function(){
    function start(){
        myFuncToBeTested();       
        setTimeout(start, 10);
        return this;
    }
    function myFunctToBeTested(){
        //Code to be tested
    }
    return {
        start: start,
        myFuncToBeTested: myFuncToBeTested
    }
})().start();

然后你可以使用你选择的测试框架进行测试:

assert( myObject.myFuncToBeTested() == expectedValue );

我想在arklord47的答案和您使用存根setTimeout的实验之间提出一个混合解决方案。像你这样的IIFE本质上很难测试,因为你没有留下任何方法来检查它是否被调用。您可以修改您的API如下:

var repeater = {
  start: function () {
    this.func();
    setTimeout(this.start.bind(this), timeout);
  },
  func: function () {
    // code to be tested
  }
};

然后你的测试可以看起来像这样(由于你标记了sinon,我已经使用了它,特别是它的假计时器API,它将允许你检查你的间隔功能):

// setup
var clock = sinon.useFakeTimers();
var spy = sinon.spy(repeater, 'func');
// test
repeater.start();
assert(spy.calledOnce);
// advance clock to trigger timeout
clock.tick(timeout);
assert(spy.calledTwice);
// advance clock again
clock.tick(timeout);
assert(spy.calledThrice);
// teardown
clock.restore();
spy.restore();