如何在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
相关产品推荐
相关产品推荐

