单元测试 – Angular 2单元测试可观察错误(HTTP)

前端之家收集整理的这篇文章主要介绍了单元测试 – Angular 2单元测试可观察错误(HTTP)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试为我的API服务编写单元测试,但在捕获HTTP错误时遇到一些问题.我跟随这个 guide以及Angular2文档,因为指南在某些小区域(稍微)过时了.

所有单元测试都与服务引发错误的单元测试分开(由于HTTP状态代码错误).我可以通过退出response.ok告诉我.从我所读到的,这与单元测试没有异步执行有关,因此,不等待错误响应.但是,我不知道为什么会出现这种情况,因为我在beforeEach方法中使用了async()实用程序函数.

API服务

get(endpoint: string,authenticated: boolean = false): Observable<any> {
    endpoint = this.formatEndpoint(endpoint);
    return this.getHttp(authenticated) // Returns @angular/http or a wrapper for handling auth headers
        .get(endpoint)
        .map(res => this.extractData(res))
        .catch(err => this.handleError(err)); // Not in guide but should work as per docs
}
private extractData(res: Response): any {
    let body: any = res.json();
    return body || { };
}

private handleError(error: Response | any): Observable<any> {
    // TODO: Use a remote logging infrastructure
    // TODO: User error notifications
    let errMsg: string;
    if (error instanceof Response) {
        const body: any = error.json() || '';
        const err: string = body.error || JSON.stringify(body);
        errMsg = `${error.status} - ${error.statusText || ''}${err}`;
    } else {
        errMsg = error.message ? error.message : error.toString();
    }
    console.error(errMsg);
    return Observable.throw(errMsg);
}

错误单元测试

// Imports

describe('Service: APIService',() => {
    let backend: MockBackend;
    let service: APIService;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            providers: [
                BaseRequestOptions,MockBackend,APIService,{
                    deps: [
                        MockBackend,BaseRequestOptions
                    ],provide: Http,useFactory: (backend: XHRBackend,defaultOptions: BaseRequestOptions) => {
                            return new Http(backend,defaultOptions);
                        }
                },{provide: AuthHttp,useFactory: (http: Http,options: BaseRequestOptions) => {
                        return new AuthHttp(new AuthConfig({}),http,options);
                    },deps: [Http,BaseRequestOptions]
                }
            ]
        });
        const testbed: any = getTestBed();
        backend = testbed.get(MockBackend);
        service = testbed.get(APIService);
    }));

    /**
     * Utility function to setup the mock connection with the required options
     * @param backend
     * @param options
     */
    function setupConnections(backend: MockBackend,options: any): any {
        backend.connections.subscribe((connection: MockConnection) => {
            const responSEOptions: any = new ResponSEOptions(options);
            const response: any = new Response(responSEOptions);
            console.log(response.ok); // Will return false during the error unit test and true in others (if spyOn log is commented).
            connection.mockRespond(response);
        });
    }

    it('should log an error to the console on error',() => {
        setupConnections(backend,{
            body: { error: `Some strange error` },status: 400
        });
        spyOn(console,'error');
        spyOn(console,'log');

        service.get('/bad').subscribe(null,e => {
            // None of this code block is executed.
            expect(console.error).toHaveBeenCalledWith("400 - Some strange error");
            console.log("Make sure an error has been thrown");
        });

        expect(console.log).toHaveBeenCalledWith("Make sure an error has been thrown."); // Fails
    });

更新1

当我检查第一个回调时,response.ok未定义.这让我相信setupConnections实用程序有问题.

it('should log an error to the console on error',async(() => {
        setupConnections(backend,'error');
        //spyOn(console,'log');

        service.get('/bad').subscribe(res => {
            console.log(res); // Object{error: 'Some strange error'}
            console.log(res.ok); // undefined
        },e => {
            expect(console.error).toHaveBeenCalledWith("400 - Some strange error");
            console.log("Make sure an error has been thrown");
        });

        expect(console.log).toHaveBeenCalledWith("Make sure an error has been thrown.");
    }));

更新2

如果不是在get方法中捕获错误而是在map中明确地执行它,那么仍然有相同的问题.

get(endpoint: string,authenticated: boolean = false): Observable<any> {
    endpoint = this.formatEndpoint(endpoint);
    return this.getHttp(authenticated).get(endpoint)
        .map(res => {
            if (res.ok) return this.extractData(res);
            return this.handleError(res);
        })
        .catch(this.handleError);
}

更新3

经过一些讨论this issue提交

From what i’ve read this has something to do with the unit tests not executing asynchronously,hence,not waiting for the error response. However,I have no idea why this is the case here since I have used the async() utility function in the beforeEach method

您需要在测试用例(它)中使用它.异步的作用是创建一个测试区域,在完成测试(或测试区域,例如beforeEach)之前等待所有异步任务完成.

因此,beforeEach中的async只是等待异步任务在退出之前在方法中完成.但它也需要同样的东西.

it('should log an error to the console on error',async(() => {

}))

UPDATE

除了丢失的异步之外,MockConnection似乎有一个错误.如果你看一下mockRespond,它总是调用next,而不考虑状态代码

mockRespond(res: Response) {
  if (this.readyState === ReadyState.Done || this.readyState === ReadyState.Cancelled) {
    throw new Error('Connection has already been resolved');
  }
  this.readyState = ReadyState.Done;
  this.response.next(res);
  this.response.complete();
}

他们有一个mockError(Error)方法,这就是调用错误

mockError(err?: Error) {
  // Matches ResourceLoader semantics
  this.readyState = ReadyState.Done;
  this.response.error(err);
}

但这不会调用允许您传递响应.这与真正的XHRConnection工作方式不一致,后者检查状态,并通过下一个或错误发送响应,但响应相同

response.ok = isSuccess(status);
if (response.ok) {
  responSEObserver.next(response);
  // TODO(gdi2290): defer complete if array buffer until done
  responSEObserver.complete();
  return;
}
responSEObserver.error(response);

对我来说听起来像个错误.你应该报告的事情.它们应该允许您在mockError中发送Response,或者在mockRespond中对它们在XHRConnection中执行相同的检查.

更新(通过OP)S​​etupConnections()

当前解决方

function setupConnections(backend: MockBackend,options: any): any {
    backend.connections.subscribe((connection: MockConnection) => {
        const responSEOptions: any = new ResponSEOptions(options);
        const response: any = new Response(responSEOptions);

        // Have to check the response status here and return the appropriate mock
        // See issue: https://github.com/angular/angular/issues/13690
        if (responSEOptions.status >= 200 && responSEOptions.status <= 299)
            connection.mockRespond(response);
        else
            connection.mockError(response);
    });
}
原文链接:https://www.f2er.com/angularjs/240352.html

猜你在找的Angularjs相关文章