Angular从Jasmine转Jest做单元测试:Observable服务方法测试报错
问题:Angular单元测试从Jasmine切换到Jest后,Observable方法测试报错
我正在将Angular单元测试从Jasmine切换到Jest,更新后的服务测试代码如下:
.... describe( 'My Test', () => { let myService: any; ... beforeEach(() => { myService = { theMethodInTheService: jest.fn() } TestBed.configureTestingModule({ .... }) myService = TestBed.inject(MyService); }) it('should fetch data from user endpoint', () => { myService.theMethodInTheService.subscribe( ( res:any ) => { expect(res).toBe('theExpectedResponse'); }); const req = httpTestingController.expectOne(theExpectedUrl); expect(req.request.method).toEqual('GET'); req.flush('theExpectedResponse'); }); })
测试失败,报错信息:
TypeError: myService.theMethodInTheService.subscribe is not a function
theMethodInTheService返回一个Observable,请问如何使用Jest进行该场景的测试?
解决方案
报错原因是你创建的mock方法theMethodInTheService: jest.fn()默认返回undefined,并非Observable,因此调用subscribe时会报错。根据测试需求,有两种可行方案:
方案1:测试真实服务的HTTP请求(推荐用于验证请求逻辑)
如果需要验证服务发起的HTTP请求细节(URL、请求方法等),并测试响应处理,直接使用真实服务配合HttpTestingController即可:
import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { MyService } from './my.service'; describe('My Test', () => { let myService: MyService; let httpTestingController: HttpTestingController; const theExpectedUrl = '目标请求URL'; beforeEach(() => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], // 必须导入该模块以支持HTTP测试 providers: [MyService] // 注入真实服务 }); myService = TestBed.inject(MyService); httpTestingController = TestBed.inject(HttpTestingController); }); afterEach(() => { // 验证所有HTTP请求都已被处理,避免遗漏 httpTestingController.verify(); }); it('should fetch data from user endpoint', () => { myService.theMethodInTheService().subscribe((res: any) => { expect(res).toBe('theExpectedResponse'); }); // 拦截预期的HTTP请求 const req = httpTestingController.expectOne(theExpectedUrl); expect(req.request.method).toEqual('GET'); // 返回模拟响应 req.flush('theExpectedResponse'); }); });
方案2:Mock服务方法返回Observable(适合隔离依赖测试)
如果不需要验证HTTP请求细节,仅需mock服务方法的返回值,只需让jest.fn()返回一个Observable即可:
import { TestBed } from '@angular/core/testing'; import { MyService } from './my.service'; import { of } from 'rxjs'; describe('My Test', () => { let myService: jest.Mocked<MyService>; beforeEach(() => { // 创建mock服务,指定方法返回Observable const mockService = { theMethodInTheService: jest.fn(() => of('theExpectedResponse')) }; TestBed.configureTestingModule({ providers: [ { provide: MyService, useValue: mockService } ] }); // 类型转换以获得Jest mock的类型提示 myService = TestBed.inject(MyService) as jest.Mocked<MyService>; }); it('should handle data from service method', () => { myService.theMethodInTheService().subscribe((res: any) => { expect(res).toBe('theExpectedResponse'); }); // 验证服务方法已被调用 expect(myService.theMethodInTheService).toHaveBeenCalled(); }); });
关键提示
jest.fn()可传入函数参数指定返回值,这里用RxJS的of()创建一个发射指定值的Observable。- 使用
jest.Mocked<MyService>替代any类型,能获得更友好的类型提示,避免类型错误。
内容的提问来源于stack exchange,提问作者k.vincent
相关产品推荐
相关产品推荐

