【问题标题】:How to test an error thrown from a subscribe如何测试订阅引发的错误
【发布时间】:2019-04-06 04:22:41
【问题描述】:

我正在 angular 4 中测试下面的调用函数。

import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  title = 'jasmine-error-test';

  constructor(private appService: AppService) { }

  ngOnInit(): void {
    this.call();
  }

  call() {
    return this.appService.load().subscribe((res) => {
      this.title = res;
    }, (err) => {
      throw new Error('Failed');
    });
  }

}

为了测试从订阅中引发错误的部分,我正在执行以下操作。

describe('when call is called', () => {
    describe('when the service returns an error', () => {
      let app;
      beforeEach(async(() => {
        const fixture = TestBed.createComponent(AppComponent);
        app = fixture.componentInstance;
        (service.load as jasmine.Spy).and.returnValue(Observable.throw({
          status: 406,
          error: {
            message: 'Test 406 error'
          }
        }));
      }));
      it('it should throw a  matching error', async(() => {
        expect(() => { app.call(); }).toThrowError('Failed');
      }));
    });
  });

但测试失败并出现错误

Expected function to throw an Error.

如果我使用调试器窗口,它会显示抛出错误的行正在被击中,但我仍然没有让测试通过。谁能告诉我这是怎么回事。

【问题讨论】:

  • 您的函数确实不会抛出任何错误。它订阅一个可观察对象,并且在您的函数返回很久之后,当错误 http 响应最终返回时,订阅时传递的错误回调会引发错误。抛出这个错误有什么意义?通过简单地让原始错误传播,您预计不会发生什么?
  • 传播是什么意思?传播到哪里?这是我的组件,没有上游。在完整的项目中,存在一个有角度的应用程序级错误处理程序组件,旨在捕获任何未处理的错误并优雅地处理它。这就是我抛出错误的原因。
  • 这是我的组件,没有上游。:因此我的问题是:抛出错误有什么意义,而不是让原始未处理的错误传播直到它到达您的应用程序级错误处理程序?您的句柄不会得到原始的、详细的 http 错误,而只会得到一个无意义的、神秘的错误,告诉“失败”。有什么意义?

标签: angular unit-testing angular-test


【解决方案1】:

有趣的问题。使用 Observables 处理错误很棘手。正如您所发现的,重新抛出错误并非易事,因为捕获此类错误的方法是在 try/catch 块中,但这不适用于异步代码。 :) 网上有很多关于这个的很好的讨论,这是我找到的一个:Error Handling in the Reactive Extensions

我建议重构您的代码。如果发生错误,您可以像使用 this.title 一样捕获组件变量中的详细信息。也许称它为this.error,然后您可以测试它是否为空(无错误)或有一个值(以防出错)。也许像这样重构:

call() {
    return this.appService.load().subscribe((res) => {
        this.title = res;
    }, (err) => {
        this.error = err;
        // throw new Error('Failed');
    });
}

那么您的测试将如下所示:

it('it should capture any error in this.error', () => {
    // expect(() => { app.call(); }).toThrowError('Failed');
    app.call();
    expect(app.error).toEqual(/* testError */);
});

如果它对你有帮助,这里是我整理的一个堆栈闪电,以尝试关于这个问题的一些想法:How to Test an Error Thrown from a Subscribe

【讨论】:

  • 感谢您的建议,我已经尝试过了,并且成功了,但是我正在编写测试并且代码最初是由其他人编写的,我不允许更改代码。不过谢谢你的回复。另外我认为在代码中有一个通用的角度错误处理程序,它应该捕获这些错误并优雅地处理它们。
猜你喜欢
  • 2021-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-03
  • 1970-01-01
  • 2021-04-09
  • 1970-01-01
相关资源
最近更新 更多