Promise.catch()不AngularJS单元测试赶上例外 [英] Promise.catch() does not catch exception in AngularJS unit test

查看:178
本文介绍了Promise.catch()不AngularJS单元测试赶上例外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写茉莉花单元测试我的打字稿的应用程序,并通过ReSharper的运行它们。据推测,如果处理程序抛出异常执行操作:

I am writing Jasmine unit tests for my app in Typescript and running them via Resharper. It is supposed to execute an action if the handler throws an exception:

describe("Q Service Test", () => {
    var q: ng.IQService;
    var rootScope: ng.IRootScopeService;

    beforeEach(inject(($q, $rootScope) => {
        q = $q;
        rootScope = $rootScope;
    }));

    it("Caught exceptions are handled properly", () => {
        var state = 'ok';
        q.when(1)
            .then(() => {
                throw new Error("test exception");
            })
            .catch(() => {
                state = 'error';
            });

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

然而,在测试失败:

However, the test is failed:

这是我的测试环境/工具的一些奇怪的行为,还是我使用不当承诺机制本身?

Is it some strange behaviour of my testing environment / tools, or am I incorrectly using the promise mechanism itself?

推荐答案

您肯定是用承诺机制的错误后,抛出一个用户定义的throw语句不构成捕获它作为一个承诺拒绝正常。正如 $ Q 文件指出:

You are definitely using the promise mechanism incorrectly, throwing a user-defined throw statement does not constitute to catching it as a promise rejection properly. As stated in the $q documentation:

在比较deferreds /承诺的行为熟悉
  的try / catch /抛出,想的拒绝作为在JavaScript中的关键字。
  这也意味着,如果你捕获通过一个承诺错误的错误
  回调,你要转发的错误源自于承诺
  目前的诺言,你必须返回一个重新抛出错误
  通过拒绝拒绝构建。

When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of reject as the throw keyword in JavaScript. This also means that if you "catch" an error via a promise error callback and you want to forward the error to the promise derived from the current promise, you have to "rethrow" the error by returning a rejection constructed via reject.

它们相似但不等同赶上用户定义的throw语句,你应该使用语句块。而 $ Q 的承诺应该只拒绝承诺。因此,在你的情况下,返回一个拒绝允诺办理的过程,而不是抛出一个用户定义的异常的正确方法。

They are similar but not equivalents, to catch user-defined throw statements, you should use catch statement blocks. While $q promises should only catch rejected promises. Thus, in your case, returning a rejected a promise is the proper way of handling the process instead of throwing a user-defined exception.

演示

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');    

  });

});

更新:

为什么你的code行为这种方式在浏览器中,是因为角度的 $ Q 实现使用的try / catch 在处理队列承诺语句块。当任何回调抛出任何错误,它捕获错误本身,除作为拒绝的理由拒绝它,后来它使用 $ exceptionHandler的来记录错误。我建议你​​只返回被拒绝的承诺。

The reason why your code behaves this way in the browser, is because Angular's $q implementation uses the try/catch statement blocks in processing the promise queue. When any of the callbacks throw any errors, it catches the error itself, rejects it with the exception as a reason for rejection, afterwards it uses $exceptionHandler to log the error. I recommend you to simply return rejected promise.

至于为什么单元测试,这样的行为的原因是因为角嘲笑实施 <一个href=\"https://docs.angularjs.org/api/ngMock/provider/$exceptionHandlerProvider\"><$c$c>$exceptionHandler是用不同的实际应用的 <$c$c>$exceptionHandler.前者创建了不同模式的供应商,默认角嘲笑实现使用重新抛出模式,这又引发异常,而不是记录它。如果您希望您的单元测试的行为方式如何默认的应用程序的 $ exceptionHandler的,那么你可以将模式设置为相同的'登录'

As for the reason why the unit tests act this way is because of angular-mocks implementation of the $exceptionHandler is different with the actual application's $exceptionHandler. The former creates a provider with different modes, the default angular-mocks implementation uses the rethrow mode which in turn throws the exception instead of logging it. If you want to have your unit tests behave the same way as how the default application's $exceptionHandler then you can set the mode to 'log'.

演示

DEMO

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');    

  });

});

这篇关于Promise.catch()不AngularJS单元测试赶上例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆