本文介绍了如何在Angular单元测试中有条件刷新$ timeout的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的代码:

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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-26 23:11