Angular 2 Observable和Promise回调单元测试

时间:2016-11-08 12:48:53

标签: javascript unit-testing angular jasmine rxjs

我在Angular 2服务中有一个方法,它获取特定用户帐户的所有详细信息 - 即登录的用户帐户 - 并返回一个Observable。

(我正在使用AngularFire2进行身份验证,以及它的价值)

如您所见,getData方法正在使用getAuth方法返回身份验证状态(作为可观察对象),而getToken方法又使用该方法(返回Promise)以获取用于填充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 Promise。

这是我的单元测试的样子:

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拒绝承诺,并测试我的观察是否会抛出。

非常感谢任何帮助或反馈。

2 个答案:

答案 0 :(得分:1)

我既不使用jasmine也不使用AngularFire2,因此我无法确定您必须做什么,但是从您的代码中可以明显看出this.getToken(authState)返回了Promise

问题来自这个Promise课程来自哪个图书馆(也就是你正在使用的polyfill)。

据我所知Promises/A的实现应该用try-catch包装回调调用,所以如果then(...)中的回调引发异常,Promise将传播到catch()。所以我猜你可以伪造来自this.http.get('myendpoint/')的回复,其中包含一些格式错误的JSON,会导致response.json()出错。

第二件事是catch()的内部回调:

.catch((error: Error) => {
    Observable.throw(new Error(`Error: ${error}`));
});

这确实没什么。没有返回语句,Observable.throw()需要出现在Observable链中才能执行某些操作。请注意,此.catch()方法来自您的Promise类,而不是来自Observable。

如果您希望它实际将错误传播给Observers,那么您必须显式调用:

.catch((error: Error) => {
    o.error(error);
});

也许如果错误冒泡到Observable.create(),它也会被传递给观察者,我对此并不确定。

答案 1 :(得分:0)

我有类似的问题,然后我使用了Observable.from:

spyOn(service, 'function').and.returnValue(Observable.fromPromise(Promise.reject({})));

您在Promise.reject中返回错误