测试返回Observable的Angular服务方法:验证setSession调用及错误处理逻辑
问题1:校验login内部对setSession的调用及参数
你原有测试失效的核心原因是没有给捕获到的HTTP请求返回模拟响应,controller.match只是匹配到了请求,但没有主动刷入返回值的情况下,Observable一直处于pending状态,subscribe里的断言、map操作符里的setSession逻辑根本不会执行。另外你不需要spylogin方法本身,我们要跑真实的login逻辑,只需要spysetSession即可。
首先先修正你代码里的明显疏漏:login方法定义的入参是3个(customerKey: string, username: string, password: string),你测试调用时只传了2个,会导致参数不匹配,下面的测试用例已补全参数。
修正后的成功场景测试代码如下:
it('login成功时应调用setSession并传入正确参数', () => { // 仅spy需要校验调用行为的setSession const setSessionSpy = spyOn(service, 'setSession'); // 调用真实login方法,参数和方法定义保持一致 service.login('testCustomerKey', accountDetails.UserName, accountDetails.Password).subscribe((res) => { // 可选校验接口返回值符合预期 expect(res).toEqual(apiResponse); }); // 匹配发出的POST请求 const req = controller.expectOne(AppConfig.apiEndPoint); // 校验请求方法、传参符合预期 expect(req.request.method).toBe('POST'); expect(req.request.body).toEqual({ Password: accountDetails.Password, UserName: accountDetails.UserName }); // 刷入模拟成功响应,此时才会触发pipe里的所有操作符逻辑 req.flush(apiResponse); // 校验setSession被调用,且传入的参数就是接口返回的响应 expect(setSessionSpy).toHaveBeenCalledOnceWith(apiResponse); // 校验无未处理的HTTP请求 controller.verify(); });
问题2:测试catchError分支逻辑
不需要mock login的返回值,只要给捕获到的请求刷入错误响应即可,完全走真实的pipe流程,同时可以验证错误处理逻辑、以及失败场景下setSession不会被调用。
测试错误场景的代码如下:
it('login请求失败时应触发错误处理逻辑', (done) => { const setSessionSpy = spyOn(service, 'setSession'); // 可选spy console.error验证错误日志输出符合预期 const consoleErrorSpy = spyOn(console, 'error'); const mockErrorMsg = 'Something happened; please try again later.'; const mockStatusCode = 401; service.login('testCustomerKey', accountDetails.UserName, accountDetails.Password).subscribe({ next: () => fail('请求失败时不应触发next回调'), error: (err) => { // 校验抛出的错误信息符合预期 expect(err).toBe(mockErrorMsg); // 校验错误日志输出符合handleError逻辑 expect(consoleErrorSpy).toHaveBeenCalledWith(`Backend returned code ${mockStatusCode}, body was: `, 'Unauthorized'); // 校验失败场景下setSession不会被调用 expect(setSessionSpy).not.toHaveBeenCalled(); done(); } }); const req = controller.expectOne(AppConfig.apiEndPoint); // 刷入错误响应,模拟后端返回401状态 req.flush('Unauthorized', { status: mockStatusCode, statusText: 'Unauthorized' }); controller.verify(); });
如果要测试网络错误(handleError中status=0的分支),只需替换刷入响应的代码为:
req.error(new ErrorEvent('Network error'), { status: 0 });
同时调整console.error的断言逻辑即可。
内容的提问来源于stack exchange,提问作者Vladyn
相关产品推荐
相关产品推荐

