You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试返回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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 08:27:03