Promise.catch()在AngularJS单元测试中没有捕获异常

时间:2015-07-21 11:54:59

标签: angularjs unit-testing typescript jasmine

我正在为Typescript中的应用编写Jasmine单元测试并通过Resharper运行它们。如果处理程序抛出异常,它应该执行一个动作:

{{1}}

然而,测试失败了:

Resharper test fail

我的测试环境/工具有些奇怪的行为,还是我错误地使用了promise机制?

2 个答案:

答案 0 :(得分:15)

您肯定使用承诺机制错误,抛出用户定义的抛出语句并不构成将其作为承诺拒绝正确使用。如$q文档中所述:

  

将延迟/承诺与熟悉的行为进行比较   try / catch / throw,将拒绝视为JavaScript中的 throw 关键字。   这也意味着如果您通过承诺错误“捕获”错误   回调,您希望将错误转发给派生自的承诺   当前的承诺,你必须通过返回一个“重新抛出”错误   通过拒绝构建拒绝。

它们类似但不等同,为了捕获用户定义的throw语句,您应该使用catch语句块。虽然$q承诺只应catch拒绝承诺。因此,在您的情况下,返回拒绝的promise是处理该过程的正确方法,而不是抛出用户定义的异常。

<强> DEMO

<强> JAVASCRIPT

describe('Q Service Test', function() {

  var $q,
      $rootScope;

  beforeEach(inject(function(_$q_, _$rootScope_) {
    $q = _$q_;
    $rootScope = _$rootScope_;
  }));

  it('Rejected promises are handled properly', function() {

    var state = 'ok';

    $q.when(1)
      .then(function() {
        return $q.reject('rejected');
      })
      .catch(function() {
        state = 'error';
      });

    $rootScope.$digest();
    expect(state).toBe('error');    

  });

});

<强>更新

您的代码在浏览器中以这种方式运行的原因是因为Angular的$q实现在处理promise队列时使用try/catch语句块。当任何回调抛出任何错误时,它会捕获错误本身,以异常作为拒绝原因拒绝它,之后它使用$exceptionHandler来记录错误。我建议你简单地回复被拒绝的承诺。

至于单元测试以这种方式行事的原因是因为angular-mocks $exceptionHandler 的实现与实际应用程序的 {{3}不同} 即可。前者创建了一个具有不同模式的提供程序,默认的角度模拟实现使用rethrow模式,而模式又抛出异常而不是记录它。如果您希望单元测试的行为与默认应用程序$exceptionHandler的行为方式相同,那么您可以将模式设置为'log'

<强> $exceptionHandler

<强> JAVASCRIPT

describe('Q Service Test', function() {

  var $q,
      $rootScope;

  beforeEach(module('ng', function($exceptionHandlerProvider) {
    $exceptionHandlerProvider.mode('log');
  }));

  beforeEach(inject(function(_$q_, _$rootScope_) {
    $q = _$q_;
    $rootScope = _$rootScope_;
  }));

  it('Caught exceptions are handled properly', function() {

    var state = 'ok';

    $q.when(1)
      .then(function() {
        throw new Error();
      })
      .catch(function() {
        state = 'error';
      });

    $rootScope.$digest();
    expect(state).toBe('error');    

  });

});

答案 1 :(得分:2)

博文Using and chaining promises in AngularJS提到,当你抛出异常时,它还会触发Angular的注册异常处理程序&#34;。所以我的猜测是Jasmine正在使用Angular的异常处理程序来监听异常。

你是否需要抛出异常,或者你可以做这样的事情:

return q.reject(new Error("test exception"));