用摩卡柴西农测试去抖动



我想测试我的debounce函数,但这同样适用于下划线或lodash。

我想用摩卡,柴的assert,可能还有西农。

我准备了一个代码笔。

Sinon的计时器让我头疼;当我要求我的去抖动首先运行时,我仍然得到一个响应,说去抖回调没有被调用,而它被调用了!

让我们看看代码:

// sinon timers
it('should not run debounced function too early', function() { 
var clock = sinon.useFakeTimers();
var delay = 100;
var targetFn = sinon.spy();
var delayedFn = g3.debounce(targetFn, {delay: delay, fireStart: false, fireLast: true});
// for lodash:
//var delayedFn = _.debounce(targetFn, delay, {leading:false, trailing:true});
delayedFn();
clock.tick(delay - 1);
clock.restore(); 
sinon.assert.notCalled(targetFn); 
});

当我们更改控制首先/最后一个运行的值时,我们从下划线中获取的错误结果。有人可以提出替代方案吗?更正?

我还在茉莉花中找到了这个测试链接。

我想将下一个块修改为摩卡:

it('should only happen once', function(){
var count = 0;
runs(function(){
var fn = underscore.debounce(function(){
count += 1;
}, 100);
fn();
fn();
fn();
});
waitsFor(function(){
return count > 0;
}, 'didnt execute', 200);
runs(function(){
expect(count).toBe(1);
});
});

这可能吗?

我只能看到这个摩卡测试成功:

it('shouldnt execute immediately', function(){
var hasHappened = false;
var fn = g3.debounce(function(){
hasHappened = true;
}, {fireFirst: false, fireLast: true, delay: 100});
chai.assert(hasHappened === false, 'error: callback has called');
fn();
chai.assert(hasHappened === false, 'error: callback has called');
});

如果你知道一堆测试用例,那就太好了,这样我就能看到我的错误。

我终于为 sinon 的错误计时器找到了解决方案,因为它们在内部覆盖了Date对象、setTimeout()setInterval()等。

这里的问题是,我们是否愿意更改代码以改变测试,或者更糟糕的是将测试条件集成到代码中。

解决方案是启动一个计时器...一次!

/*** file 'g3.debounceTest.js' ***/
describe('g3.debounce', function() {
it('should not run debounced function with: 1 call at elapsed < delay & fireLast: true', function() { 
var clock = sinon.useFakeTimers();
// sinon remedy avoids buggy behavior
clock.tick(1000);
//console.log(Date.now());
var delay = 100;
var spy = sinon.spy();
var targetFn = function(){console.log('eventually debounced was called!'); spy()};
var delayedFn = g3.debounce(targetFn, {delay: delay, fireFirst: false, fireLast: true});
// for lodash:
//var delayedFn = _.debounce(targetFn, delay, {leading: false, trailing: true});
delayedFn();
clock.tick(delay - 1);
//console.log(Date.now());
clock.restore(); 
sinon.assert.notCalled(spy); 
});
it('should run debounced function once with: 1 call at elapsed < delay & fireFirst: true', function() { 
var clock = sinon.useFakeTimers();
// sinon remedy avoids buggy behavior
clock.tick(1000);
//console.log(Date.now());
var delay = 100;
var spy = sinon.spy();
var targetFn = function(){console.log('eventually debounced was called!'); spy()};
var delayedFn = g3.debounce(targetFn, {delay: delay, fireFirst: true, fireLast: false});
// for lodash:
//var delayedFn = _.debounce(targetFn, delay, {leading: true, trailing: false});
delayedFn();
clock.tick(delay - 1);
//console.log(Date.now());
clock.restore(); 
sinon.assert.calledOnce(spy); 
});
it('should run debounced function once with: 3 calls at elapsed < delay & fireFirst: true', function() { 
var clock = sinon.useFakeTimers();
// sinon remedy avoids buggy behavior
clock.tick(1000);
//console.log(Date.now());
var delay = 100;
var spy = sinon.spy();
var targetFn = function(){console.log('eventually debounced was called!'); spy()};
var delayedFn = g3.debounce(targetFn, {delay: delay, fireFirst: true, fireLast: false});
// for lodash:
//var delayedFn = _.debounce(targetFn, delay, {leading: true, trailing: false});
/* 1 */delayedFn();
/* after 99ms */
clock.tick(delay - 1);
//console.log(Date.now());
/* 2 */delayedFn();
/* after 99ms */
clock.tick(delay - 1);
//console.log(Date.now());
/* 3 */delayedFn();
clock.restore(); 
sinon.assert.calledOnce(spy); 
});
it('should run debounced function once with: 3 calls at elapsed < delay & fireLast: true', function() { 
var clock = sinon.useFakeTimers();
// sinon remedy avoids buggy behavior
clock.tick(1000);
//console.log(Date.now());
var delay = 100;
var spy = sinon.spy();
var targetFn = function(){console.log('eventually debounced was called!'); spy()};
var delayedFn = g3.debounce(targetFn, {delay: delay, fireFirst: false, fireLast: true});
// for lodash:
//var delayedFn = _.debounce(targetFn, delay, {leading: true, trailing: false});
/* 1 */delayedFn();
/* after 99ms */
clock.tick(delay - 1);
//console.log(Date.now());
/* 2 */delayedFn();
/* after 99ms */
clock.tick(delay - 1);
//console.log(Date.now());
/* 3 */delayedFn();
/* after 100ms */
clock.tick(delay);
clock.restore();
sinon.assert.calledOnce(spy);
});
});
/***end file 'g3.debounceTest.js' ***/

我还在回调中注入了一个spy(),因为我想看看该回调会发生什么,我惊讶地注意到回调在我们调用clock.restore();后运行,但sinon没有办法对此进行审核,并且仍然完全不知道clock.restore();之后会发生什么。

这就是为什么我在最后一个案例中强迫写clock.tick(delay);,以便sinon"看到"最后一次调用发生。

最后,如果你有更多的想法来测试这样的异步代码,我很想看到它们。

最新更新