如何测试订阅引发的错误

Rup*_*Roy 6 unit-testing angular angular-test

我正在 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');
    });
  }

}
Run Code Online (Sandbox Code Playgroud)

为了测试订阅抛出错误的部分,我正在执行以下操作。

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');
      }));
    });
  });
Run Code Online (Sandbox Code Playgroud)

但测试失败并出现错误

Expected function to throw an Error.
Run Code Online (Sandbox Code Playgroud)

如果我使用调试器窗口,它会显示抛出错误的行正在被命中,但我仍然没有让测试通过。有人可以让我知道发生了什么事吗?

dmc*_*dle 3

有趣的问题。使用 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');
    });
}
Run Code Online (Sandbox Code Playgroud)

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

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

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