javascript - Angular 2 Observable 和 Promise 回调单元测试

标签 javascript unit-testing angular jasmine rxjs

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

(我正在使用 AngularFire2 进行身份验证,因为它的值(value))

如您所见,getData 方法使用 getAuth 方法,该方法返回身份验证状态(作为可观察的),而该状态又由 使用>getToken 方法(返回 Promise)来获取用于填充 Authorization header 并执行 http 请求的 token 。 (我确实知道我的代码可能需要重构,如果有任何反馈,我将不胜感激)

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}`));
            });
        });
    });
}

我是单元测试的新手,并且一直在尝试测试此方法,但我仍然无法覆盖该方法内 Promise 的 .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 拒绝 Promise,并测试我的可观察对象是否会抛出异常。

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

最佳答案

我既不使用 jasmine 也不使用 AngularFire2,所以我无法告诉你到底需要做什么,但从你的代码中可以明显看出 this.getToken(authState) 返回一个Promise

问题是这个Promise类来自哪个库(又名您正在使用的polyfill)。

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

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

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

这实际上没有任何作用。没有 return 语句,并且 Observable.throw() 需要出现在 Observable 链中才能执行某些操作。请注意,这个 .catch() 方法来自 Promise 类,而不是来自 Observable。

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

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

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

关于javascript - Angular 2 Observable 和 Promise 回调单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40487388/

相关文章:

javascript - #9 挑战 - 了解您的 Node (异步回调)

javascript - 如何通过函数调用设置图像的src?

c# - 使用 Flurl GetResponseJson<TError>() 进行单元测试代码

Angular - 终止 Observables 的首选方式是什么?

Angular:如何重置 matChipList 输入字段和 Google Recaptcha?

javascript - 在 Angular App 中使用 Observables 和过滤数组列表

javascript - 如何让计算机猜测一个数字并返回猜测的数字(Javascript)?

javascript - 如何在页面提交时自动滚动到页面顶部

python - 我应该将正在测试的函数包含在unittest文件中,还是应该将其导入unittest文件中?

ios - 如何为 Alamofire 请求函数编写单元测试?