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

Angular Jest单元测试如何mock Promise覆盖signMessage的if分支

问题描述

现有如下方法实现:

async signMessage(xml, mbo): Promise<any> {
  try {
    const isSignatureAppAlive = await this.pingDigitalSignatureApp().toPromise();

    if (isSignatureAppAlive.alive) {
      try {
        this.signedMsg = await this.getSignedMsg(xml, mbo).toPromise();
        return this.signedMsg;
      } catch (er) {
        return this.handleSignatureAppErrorCodes(er.error.errorCode);
      }
    }
  } catch (e) {
    this.showSignatureInfoModal();
    return this.handleError({ message: 'empty' });
  }
}
getSignedMsg(msg, mbo): Observable<any> {
  this.signDocument.title = '';
  this.signDocument.content = btoa(msg);
  this.signDocument.contentType = 'application/xml';
  this.signDocument.uriOrIdToSign = '';

  this.postParam.certificateAlias = mbo;
  this.postParam.digestAlgorithm = 'SHA1';
  this.postParam.documents = [];
  this.postParam.documents.push(this.signDocument);
  this.postParam.signingMethod = 'xmldsig';
  this.postParam.envelopingMethod = 'enveloped';

  return this.http.post<any>(SERVICE_URL + 'sign', this.postParam, httpOptions).pipe();
}

目前已编写覆盖错误捕获场景的测试用例:

service.signMessage('xml', 'mbo').catch((errCode) => {
  expect(errCode).toBe('empty');
  done();
});

需要补充什么逻辑才能覆盖方法内的if语句分支?是否需要mock Promise?曾尝试编写如下测试用例:

it('signMessage', async (done) => {
  const spy = spyOn(service, 'pingDigitalSignatureApp').and.returnValue(
    new Promise((resolve) => resolve('someVal')),
  );
  service.pingDigitalSignatureApp();
  expect(spy).toHaveBeenCalled();
  done();
});

该用例执行后未达到预期效果,测试逻辑并未进入if语句分支,需要相关解决方案建议。


问题原因

之前写的测试没进入if分支,核心问题有3个:

  • pingDigitalSignatureApp 本身返回Observable类型,直接mock返回Promise,和原代码调用.toPromise()转Promise的逻辑不匹配
  • mock的resolve值是字符串'someVal',原代码判断条件是isSignatureAppAlive.alive,字符串不存在alive属性,会被判定为假值,自然进不去if块
  • 测试逻辑里直接调用了service.pingDigitalSignatureApp(),根本没有调用被测目标signMessage方法,逻辑不可能走到if分支
覆盖if分支的测试方案

要覆盖if (isSignatureAppAlive.alive === true)分支,按以下规则mock即可:

  • 把pingDigitalSignatureApp mock成返回Observable,这个Observable吐出的对象必须带alive: true属性
  • 要覆盖if块内签名成功的分支,同步mock getSignedMsg 方法返回成功的Observable
  • 要覆盖if块内签名失败的内层catch分支,mock getSignedMsg 返回抛出指定结构错误的Observable

注意:用到的of、throwError是RxJS提供的构造方法,需要从rxjs包导入,不要手动返回原生Promise,避免和原方法的Observable调用链不匹配。

参考测试用例

覆盖「签名服务存活+签名成功」分支

it('should enter if branch when signature app is alive and sign success', async () => {
  // mock ping方法返回alive为true的Observable
  spyOn(service, 'pingDigitalSignatureApp').and.returnValue(
    of({ alive: true })
  );
  // mock getSignedMsg返回成功的签名结果
  const mockSignedResult = 'mock-signed-msg';
  spyOn(service, 'getSignedMsg').and.returnValue(of(mockSignedResult));
  spyOn(service, 'handleSignatureAppErrorCodes');

  // 调用被测方法
  const result = await service.signMessage('test-xml', 'test-mbo');

  // 断言逻辑符合预期
  expect(service.pingDigitalSignatureApp).toHaveBeenCalled();
  expect(service.getSignedMsg).toHaveBeenCalledWith('test-xml', 'test-mbo');
  expect(result).toBe(mockSignedResult);
  expect(service.signedMsg).toBe(mockSignedResult);
  expect(service.handleSignatureAppErrorCodes).not.toHaveBeenCalled();
});

覆盖「签名服务存活+签名接口报错」分支

it('should handle sign error when signature app is alive but sign request failed', async () => {
  // mock ping返回alive:true
  spyOn(service, 'pingDigitalSignatureApp').and.returnValue(of({ alive: true }));
  // mock getSignedMsg返回错误,错误结构匹配原代码取值逻辑er.error.errorCode
  const mockErrorCode = 'ERR_SIGN_FAILED';
  const mockError = { error: { errorCode: mockErrorCode } };
  spyOn(service, 'getSignedMsg').and.returnValue(throwError(() => mockError));
  spyOn(service, 'handleSignatureAppErrorCodes').and.returnValue(mockErrorCode);

  const result = await service.signMessage('test-xml', 'test-mbo');

  expect(service.getSignedMsg).toHaveBeenCalledWith('test-xml', 'test-mbo');
  expect(service.handleSignatureAppErrorCodes).toHaveBeenCalledWith(mockErrorCode);
  expect(result).toBe(mockErrorCode);
});

如果要覆盖「签名服务不存活」的分支(if条件不满足场景),只需要把ping方法的返回值改成of({ alive: false })即可,此时if块不会执行,方法最终会返回undefined,可根据业务逻辑补充对应断言。

内容的提问来源于stack exchange,提问作者fadingbeat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 14:01:14