我在Angular 2的服务中有一个方法,它可以获取一个特定用户账户的所有详细信息——也就是已经登录的那个账户——并返回一个Observable。
(我使用AngularFire2进行身份验证,因为它是值得的)
正如你所看到的,getData
方法正在使用返回身份验证状态的getAuth
方法(作为一个可观察对象),这反过来又被getToken
方法(返回一个承诺)使用,以获得用于填充Authorization
标头并执行http请求的令牌。
getData(): Observable<IData> {
let authHeaders = new Headers();
return Observable.create((o: Observer<IData>) => {
this.getAuth().subscribe((authState: IState) => {
this.getToken(authState).then(token => {
/* ...
* Do things with that token, call an http service etc.
*/ ...
authHeaders.set('Authorization', token);
this.http.get('myendpoint/', {
headers: this.authHeaders
})
.map((response: Response) => response.json())
.map((data: IData) => {
o.next(data);
});
})
.catch((error: Error) => {
Observable.throw(new Error(`Error: ${error}`));
});
});
});
}
我是单元测试的新手,并且一直在尝试测试这个方法,但我仍然无法覆盖该方法内的承诺的.catch
。
我的单元测试如下:
describe('Service: UserDataService', () => {
let mockHttp: Http;
let service: UserDataService;
let getAuthSpy: jasmine.Spy;
let getTokenSpy: jasmine.Spy;
beforeEach(() => {
mockHttp = { get: null } as Http;
TestBed.configureTestingModule({
providers: [
{ provide: Http, useValue: mockHttp },
AngularFire,
UserDataService,
]
});
service = new UserDataService(AngularFire, mockHttp);
spyOn(mockHttp, 'get').and.returnValue(Observable.of({
json: () => {
"nickname": "MockNickname"
}
}));
getAuthSpy = spyOn(service, 'getAuth').and.returnValue(Observable.of({
"auth": {
"uid": "12345"
}));
getTokenSpy = spyOn(service, 'getToken').and.returnValue(new Promise((resolve, reject) => {
resolve('test promise response');
}));
});
describe('getLead', () => {
beforeEach(() => {
spyOn(service, 'getLead').and.callThrough();
});
it('should return an object of user data and set the dataStore.userEmail if state exists', () => {
service.getLead().subscribe(res => {
expect(res).toEqual(jasmine.objectContaining({
nickname: 'MockNickname'
}));
});
expect(service.getLead).toHaveBeenCalled();
});
it('should throw, if no authState is provided', () => {
getAuthSpy.and.returnValue(Observable.of(false));
service.getLead();
expect(service.getLead).toThrow();
});
it('should throw, if getToken() fails to return a token', () => {
getTokenSpy.and.returnValue(new Promise((resolve, reject) => {
reject('test error response');
}));
/*
* This is where I am getting lost
*/
service.getLead();
expect(service.getLead).toThrow();
});
});
});
根据我的理解,我必须以某种方式使getToken
的承诺拒绝,并测试看看我的可观察对象是否会抛出。
任何帮助或反馈非常感谢。
我不使用jasmine
也不使用AngularFire2,所以我不能告诉你到底要做什么,但从你的代码很明显,this.getToken(authState)
返回Promise
。
问题是这个Promise
类来自什么库(也就是你正在使用的polyfill)。
据我所知,承诺/A的实现应该用try - catch包装回调调用,所以如果你在then(...)
的回调抛出一个异常,承诺将传播到catch()
。所以我猜你可以用一些格式错误的JSON来伪造this.http.get('myendpoint/')
的响应,这会导致response.json()
的错误。
catch()
的内部回调:
.catch((error: Error) => {
Observable.throw(new Error(`Error: ${error}`));
});
这实际上没有任何作用。没有返回语句,Observable.throw()
需要出现在Observable链中来做一些事情。注意,这个.catch()
方法来自你的Promise类,而不是Observable。
如果你想让它将错误传播给观察者,那么你必须显式调用:
.catch((error: Error) => {
o.error(error);
});
也许如果错误冒起到Observable.create()
,它也会传递给观察者,我不确定这一点
我也有类似的问题,然后我使用了Observable.from:
spyOn(service, 'function').and.returnValue(Observable.fromPromise(Promise.reject({})));
在Promise.reject