问题描述
我有这样的代码:
function doThing() {
if (invalidInput) {
console.error('Invalid input.');
return;
}
$timeout(function() {
MyService.doThing();
}, 1000);
}
我想测试传入无效输入时是否未调用MyService.doThing
.
I want to test that MyService.doThing
isn't called when invalid input is passed in.
如果我不做$timeout.flush()
而是呼叫doThing(invalidInput)
,则无论我是否有第2-5行,都不会调用MyService.doThing
.因此,要真正测试传入无效输入时是否调用MyService.doThing
,我需要调用$timeout.flush
.
If I call doThing(invalidInput)
without doing $timeout.flush()
, MyService.doThing
wouldn't be called, regardless of whether I have lines 2-5. So to really test whether MyService.doThing
is called when invalid input is passed in, I need to call $timeout.flush
.
问题是,如果我没有刷新要尝试刷新,则会引发错误. Error: No deferred tasks to be flushed
.
The problem is that it throws an error if I try to flush when there's nothing to flush. Error: No deferred tasks to be flushed
.
如何处理这种情况?我想做类似$timeout.flushIfFlushable()
的事情.
How can I handle this scenario? I'd like to do something like, $timeout.flushIfFlushable()
.
推荐答案
在单元测试中不存在不确定性,应该可以预见是否有要冲刷$timeout
的东西.
No uncertainty is welcome in unit tests, it should be predictable whether there is something to flush for $timeout
or not.
在这段代码中,应该测试两种情况,在两个$timeout
中都不应该是黑匣子,而应该是存根(可以选择是一个间谍,它包裹了真实的服务).
In this piece of code two cases should be tested, in both $timeout
shouldn't be a blackbox, it should be a stub instead (optionally a spy that wraps around the real service).
beforeEach(module('app', ($provide) => {
$provide.decorator('$timeout', ($delegate) => {
var timeoutSpy = jasmine.createSpy().and.returnValue($delegate);
// methods aren't copied automatically to spy
return angular.extend(timeoutSpy, $delegate);
});
}));
第一个是假invalidInput
:
...
MyService.doThing();
expect($timeout).not.toHaveBeenCalled();
第二个是真实的invalidInput
:
...
MyService.doThing();
expect($timeout).toHaveBeenCalledWith(jasmine.any(Function), 1000);
$timeout.flush();
expect(MyService.doThing).toHaveBeenCalledTimes(2);
不管这种情况,从承诺驱动的函数中返回承诺通常是一件好事:
Disregarding this case, it is generally a good thing to return promises from promise-powered functions:
function doThing() {
if (invalidInput) {
console.error('Invalid input.');
return;
}
return $timeout(function() {
return MyService.doThing();
}, 1000);
}
通过这种方式,调用者(最有可能的规范)可以控制函数的异步行为.
This way the callers (most likely specs) may have some control on function's asynchronous behaviour.
直接回答问题,执行'flushIfFlushable()'的预期方法是
Answering the question directly, the expected way to do 'flushIfFlushable()' is
try {
$timeout.verifyNoPendingTasks(); // just for semantics, not really necessary
$timeout.flush();
} catch (e) {}
出于上述原因应避免使用.
Which should be avoided for the reasons listed above.
这篇关于如何在Angular单元测试中有条件刷新$ timeout的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!