Jac*_*sor 6 unit-testing angular2-testing angular2-observables angular
我正在尝试为我的API服务编写单元测试,但在捕获HTTP错误时遇到一些问题.我遵循本指南以及Angular2文档,因为该指南在某些小范围内(稍微)过时了.
所有单元测试都与服务引发错误的单元测试分开(由于HTTP状态代码错误).我可以通过退出告诉我response.ok.从我所读到的,这与单元测试没有异步执行有关,因此,不等待错误响应.但是,我不知道为什么会出现这种情况,因为我async()在beforeEach方法中使用了效用函数.
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);
}
Run Code Online (Sandbox Code Playgroud)
// 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
});
Run Code Online (Sandbox Code Playgroud)
当我检查第一个回调时,response.ok未定义.这让我相信setupConnections公用事业有些不对劲.
it('should log an error to the console on error', async(() => {
setupConnections(backend, {
body: { error: `Some strange error` },
status: 400
});
spyOn(console, '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.");
}));
Run Code Online (Sandbox Code Playgroud)
如果不是在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);
}
Run Code Online (Sandbox Code Playgroud)
经过一番讨论后提交了这个问题
据我所知,这与单元测试不异步执行有关,因此不等待错误响应。但是,我不知道为什么会出现这种情况,因为我在方法中使用了
async()实用函数beforeEach
您需要在测试用例( )中使用它it。所做async的是创建一个测试区域,等待所有异步任务完成后再完成测试(或测试区域,例如beforeEach)。
因此,在退出方法之前,它async只是beforeEach等待方法中的异步任务完成。但他们it也需要同样的东西。
it('should log an error to the console on error', async(() => {
}))
Run Code Online (Sandbox Code Playgroud)
除了缺失之外async,似乎还有一个错误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();
}
Run Code Online (Sandbox Code Playgroud)
他们有一个mockError(Error)方法,这就是所谓的error
mockError(err?: Error) {
// Matches ResourceLoader semantics
this.readyState = ReadyState.Done;
this.response.error(err);
}
Run Code Online (Sandbox Code Playgroud)
但这并不允许您传递Response. 这与真实的工作方式不一致XHRConnection,真实的工作方式检查状态,并Response通过nextor发送error,但是相同的Response
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);
Run Code Online (Sandbox Code Playgroud)
对我来说听起来像是一个错误。您可能应该报告一些事情。他们应该允许您发送Response或进行与 中mockError相同的检查。mockRespondXHRConnection
目前的解决方案
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);
});
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5636 次 |
| 最近记录: |