如何对这个从管道可观察到的错误捕获的 Angular 打字稿 Http 错误拦截器进行单元测试?

Posted

技术标签:

【中文标题】如何对这个从管道可观察到的错误捕获的 Angular 打字稿 Http 错误拦截器进行单元测试?【英文标题】:How to unit test this Angular typescript Http Error Interceptor that catches errors from a piped observable? 【发布时间】:2019-05-10 01:37:52 【问题描述】:

我正在进行一项实验,通过测试其他人的代码(例如自动化单元和端到端测试)来学习角度和打字稿。在我对其进行测试后,我计划将其重新用于我正在为大学教室进行的宠物项目。

我从这里开始对代码进行至少一半的单元测试:http://jasonwatmore.com/post/2018/05/16/angular-6-user-registration-and-login-example-tutorial

一段时间以来,我一直在尝试对以下代码进行单元测试,但到目前为止,我从自己的想法或互联网上的想法中尝试的一切都没有成功:

import  HttpInterceptor, HttpRequest, HttpHandler, HttpEvent  from "@angular/common/http";
import  AuthenticationService  from "src/app/authenticationService/AuthenticationService";
import  Observable, throwError  from "rxjs";
import  catchError  from "rxjs/operators";
import  Injectable  from "@angular/core";

@Injectable()
export class ErrorInterceptor implements HttpInterceptor 
    constructor(private authenticationService: AuthenticationService) 

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> 
        console.log('before error handle')
        return next.handle(request).pipe(catchError(err => 

            console.log('in error handle')

            if (err.status === 401)  
                // auto logout if 401 response returned from api
                this.authenticationService.logout();
                location.reload(true);
            

            const error = err.error.message || err.statusText;
            return throwError(error);
        ))
    


以下测试代码和几个变体未能成功让“错误句柄”消息显示在控制台日志中:

import  ErrorInterceptor  from "./ErrorInterceptor";
import  of, throwError, defer  from "rxjs";

describe('ErrorInterceptor', () => 
    let errorInterceptor;
    let authenticationServiceSpy;

    beforeEach(() => 
        authenticationServiceSpy = jasmine.createSpyObj('AuthenticationService', ['logout']);
        errorInterceptor = new ErrorInterceptor(authenticationServiceSpy);
    )

    it('should create', () => 
        expect(errorInterceptor).toBeTruthy();
    )

    describe('intercept', () => 
        let httpRequestSpy;
        let httpHandlerSpy;
        const error = status: 401, statusText: 'error';

        it('should auto logout if 401 response returned from api', () => 
            //arrange
            httpRequestSpy = jasmine.createSpyObj('HttpRequest', ['doesNotMatter']);
            httpHandlerSpy = jasmine.createSpyObj('HttpHandler', ['handle']);
            httpHandlerSpy.handle.and.returnValue(
                pipe: () => 
                return fakeAsyncResponseWithError();
                
            );

            //act
            errorInterceptor.intercept(httpRequestSpy, httpHandlerSpy);

            //assert
            //TBD

            function fakeAsyncResponseWithError<T>(data: T) 
                return defer(() => throwError(error));
            
        )
    )
)

【问题讨论】:

【参考方案1】:

这里有几个问题。

首先,httpHandlerSpy.handle() 的返回值必须是 Observable,因为上面已经有管道运算符,然后 HttpInterceptor 代码可以根据需要通过管道将其传递给 catchError。 其次,HttpInterceptor 返回一个 Observable,要“执行”它,需要订阅它。

我整理了一个Stackblitz 来展示我将如何处理这个问题。

来自 Stackblitz,这是规范(it 函数):

it('should auto logout if 401 response returned from api', () => 
    //arrange
    httpRequestSpy = jasmine.createSpyObj('HttpRequest', ['doesNotMatter']);
    httpHandlerSpy = jasmine.createSpyObj('HttpHandler', ['handle']);
    httpHandlerSpy.handle.and.returnValue(throwError(
        error: 
            message: 'test-error'
        
    ));
    //act
    errorInterceptor.intercept(httpRequestSpy, httpHandlerSpy)
        .subscribe(
            result => console.log('good', result), 
            err =>  
                console.log('error', err);
                expect(err).toEqual('test-error');
            
        );

    //assert

)

我希望这会有所帮助。

【讨论】:

真的很感激。谢谢!它不仅彻底简洁地回答了我的问题,而且还通过一些可运行的演示代码在此过程中教授了一些东西。 这个答案对我也有帮助。谢谢:-) @dmcgrandle,你能回答这个问题吗:***.com/questions/63555118/… 我有 2 个私有方法。

以上是关于如何对这个从管道可观察到的错误捕获的 Angular 打字稿 Http 错误拦截器进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

在模板中使用异步管道可观察到的不适用于单个值

在可管道 rxjs 运算符的组合管道中捕获错误

RxSwift - 来自可观察到的忽略错误的驱动程序

RxSwift 可观察到的错误停止链 - 带有 Rx 的 Web 服务,如何恢复?

如何捕获测试中可观察订阅抛出的异常

使用异步管道从可观察对象中读取对象字段