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

如何在Angular6的Jasmine中测试含map与mergeMap的API服务函数

Angular服务函数saveAndReloadData的Jasmine测试方案

针对你提供的先POST保存再GET重载数据的服务函数,我们可以通过Angular的HttpTestingController模拟HTTP请求,覆盖所有关键场景的测试:

测试前置准备

先配置测试模块,注入目标服务和HttpTestingController:

import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { YourDataService } from './your-data.service'; // 替换为你的服务类名
import { DataResponseModel } from './data-response.model'; // 替换为你的模型类
import { throwError } from 'rxjs';

describe('YourDataService', () => {
  let service: YourDataService;
  let httpMock: HttpTestingController;
  const mockRemoteApiUrl = 'http://example.com/api'; // 模拟API地址

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [YourDataService]
    });
    service = TestBed.inject(YourDataService);
    httpMock = TestBed.inject(HttpTestingController);
    // 替换服务内的API地址(若属性私有,通过方括号访问)
    service['_remoteApiUrl'] = mockRemoteApiUrl;
    // 模拟初始提交数据
    service['initialdetails'] = { /* 你的初始数据结构 */ };
  });

  afterEach(() => {
    // 验证所有HTTP请求已处理,避免内存泄漏
    httpMock.verify();
  });

  // 测试用例
});

测试场景1:正常流程(POST成功+GET成功)

验证POST无错误时,会触发后续GET请求,且正确赋值FinalDetails并返回数据:

it('should save data via POST then fetch details via GET on success', (done) => {
  const testRefNo = 'REF123';
  const mockPostSuccessResp = { hasErrors: false, result: 'saved' };
  const mockGetResp: DataResponseModel = { /* 你的响应数据结构 */ };

  service.saveAndReloadData(testRefNo).subscribe({
    next: (data) => {
      expect(data).toEqual(mockGetResp);
      expect(service['FinalDetails']).toEqual(mockGetResp);
      done();
    },
    error: () => fail('不应触发错误')
  });

  // 拦截并处理POST请求
  const postReq = httpMock.expectOne(`${mockRemoteApiUrl}/Savedata`);
  expect(postReq.request.method).toBe('POST');
  expect(postReq.request.body).toEqual(service['initialdetails']);
  postReq.flush(mockPostSuccessResp);

  // 拦截并处理GET请求
  const getReq = httpMock.expectOne(`${mockRemoteApiUrl}/GetDetails?refNo=${testRefNo}`);
  expect(getReq.request.method).toBe('GET');
  getReq.flush(mockGetResp);
});

测试场景2:POST返回hasErrors

验证POST返回hasErrors: true时,抛出错误且不发起GET请求:

it('should throw error when POST returns hasErrors: true', (done) => {
  const testRefNo = 'REF123';
  const mockPostErrorResp = { hasErrors: true, resultDescription: '保存失败' };
  spyOn(service, 'handleError').and.returnValue(throwError(() => new Error('处理后的错误')));

  service.saveAndReloadData(testRefNo).subscribe({
    next: () => fail('不应触发成功回调'),
    error: (err) => {
      expect(err.message).toBe('处理后的错误');
      expect(service.handleError).toHaveBeenCalledWith(mockPostErrorResp.resultDescription);
      done();
    }
  });

  // 拦截POST请求并返回错误响应
  const postReq = httpMock.expectOne(`${mockRemoteApiUrl}/Savedata`);
  postReq.flush(mockPostErrorResp);

  // 验证无GET请求发起
  httpMock.expectNone(`${mockRemoteApiUrl}/GetDetails?refNo=${testRefNo}`);
});

测试场景3:POST请求失败(网络错误)

验证POST请求本身失败时,错误被handleError处理且不发起GET:

it('should handle POST request failure', (done) => {
  const testRefNo = 'REF123';
  const mockError = new Error('网络错误');
  spyOn(service, 'handleError').and.returnValue(throwError(() => mockError));

  service.saveAndReloadData(testRefNo).subscribe({
    next: () => fail('不应触发成功回调'),
    error: (err) => {
      expect(err).toBe(mockError);
      expect(service.handleError).toHaveBeenCalledWith(mockError);
      done();
    }
  });

  // 拦截POST请求并模拟错误
  const postReq = httpMock.expectOne(`${mockRemoteApiUrl}/Savedata`);
  postReq.error(new ProgressEvent('网络错误'));

  // 验证无GET请求发起
  httpMock.expectNone(`${mockRemoteApiUrl}/GetDetails?refNo=${testRefNo}`);
});

测试场景4:GET请求失败

验证POST成功后,GET请求失败时错误被handleError处理:

it('should handle GET request failure after successful POST', (done) => {
  const testRefNo = 'REF123';
  const mockPostSuccessResp = { hasErrors: false };
  const mockGetError = new Error('获取数据失败');
  spyOn(service, 'handleError').and.returnValue(throwError(() => mockGetError));

  service.saveAndReloadData(testRefNo).subscribe({
    next: () => fail('不应触发成功回调'),
    error: (err) => {
      expect(err).toBe(mockGetError);
      expect(service.handleError).toHaveBeenCalledWith(mockGetError);
      done();
    }
  });

  // 处理POST请求
  const postReq = httpMock.expectOne(`${mockRemoteApiUrl}/Savedata`);
  postReq.flush(mockPostSuccessResp);

  // 处理GET请求并模拟错误
  const getReq = httpMock.expectOne(`${mockRemoteApiUrl}/GetDetails?refNo=${testRefNo}`);
  getReq.error(new ProgressEvent('获取失败'));
});

注意事项

  • 若服务中_remoteApiUrl、initialdetails、FinalDetails为私有属性,可通过service['propertyName']访问,或在服务中添加测试专用的访问方法。
  • handleError若为私有方法,Angular测试允许通过spyOn(service, 'handleError')模拟其行为。
  • 异步测试需调用done()通知Jasmine测试完成,避免超时。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:54:30