如何用Jest测试含RxJS .pipe的代码?遇pipe未定义错误
问题:Jest测试RxJS pipe时出现"Cannot read properties of undefined (reading 'pipe')"错误
我有一段服务代码,通过this.httpService.post发起请求,并用RxJS的.pipe结合catchError处理错误。编写Jest测试时,我mock了httpService.post让它返回Observable对象,但测试执行到.pipe时抛出错误:TypeError: Cannot read properties of undefined (reading 'pipe')。
待测试代码
const { data: plan } = await firstValueFrom( this.httpService .post<CreatePlanPagarmeInterface>( `${PagarmeConfig.baseUrl}/plans`, pagarmeBody, PagarmeConfig.auth, ) .pipe( catchError(() => { throw new BadRequestException( 'Error to create plan.', ); }), ), );
测试代码
describe('createPlanMonth', () => { it('shoud be able to create a new plan month', async () => { jest.spyOn(httpService, 'post').mockReturnValueOnce( of({ status: 200, statusText: 'OK', config: {}, headers: {}, data: resultPagarmeMock, }), ); const result = await planService.createPlanMonth(mockPlan); expect(result).toEqual(resultMockPlan); }); });
解决方案
原因
错误核心是this.httpService.post()调用后返回了undefined,而非预期的Observable,导致后续.pipe调用失败。通常是因为mock的httpService.post没有绑定到服务实际使用的实例上。
修复步骤
- 注入正确的mock实例:如果是NestJS这类依赖注入框架,需在测试模块中显式提供mock的
HttpService,确保服务使用的是该mock对象而非真实实例。 - 正确获取mock实例并spy:通过测试模块拿到
httpService的mock实例后,再对其post方法进行spy,保证mock真正生效。 - 验证Observable返回值:确保测试代码正确导入RxJS的
of操作符,返回合法的Observable对象。
修正后的测试代码示例
import { of } from 'rxjs'; import { Test, TestingModule } from '@nestjs/testing'; import { PlanService } from './plan.service'; import { HttpService } from '@nestjs/axios'; import { PagarmeConfig } from './config/pagarme.config'; // 定义你的mock数据 const resultPagarmeMock = { /* 模拟的Pagarme返回数据 */ }; const mockPlan = { /* 模拟的入参数据 */ }; const resultMockPlan = { /* 预期的返回结果 */ }; describe('PlanService', () => { let planService: PlanService; let httpService: HttpService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ PlanService, { provide: HttpService, useValue: { post: jest.fn() }, // 初始化mock的post方法 }, ], }).compile(); planService = module.get<PlanService>(PlanService); httpService = module.get<HttpService>(HttpService); }); describe('createPlanMonth', () => { it('should be able to create a new plan month', async () => { jest.spyOn(httpService, 'post').mockReturnValueOnce( of({ status: 200, statusText: 'OK', config: {}, headers: {}, data: resultPagarmeMock, }), ); const result = await planService.createPlanMonth(mockPlan); expect(result).toEqual(resultMockPlan); // 验证post方法的调用参数是否符合预期 expect(httpService.post).toHaveBeenCalledWith( `${PagarmeConfig.baseUrl}/plans`, expect.any(Object), // 替换为实际的pagarmeBody参数 PagarmeConfig.auth, ); }); }); });
关键修复点
- 在测试模块的
providers中提前配置mock的HttpService,确保服务依赖的是该mock实例 - 通过
module.get获取mock实例后再执行spy,避免spy对象与服务实际使用对象不匹配 - 增加对
post方法调用参数的断言,验证请求逻辑的正确性
内容的提问来源于stack exchange,提问作者wiliamvj
相关产品推荐
相关产品推荐

