Angular 2的Observable和Promise回调单元测试



我在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

中返回错误

最新更新