在Jasmine与RxJS中模拟HTTP错误Observable的测试问题
问题描述
在Jasmine测试中,组件的服务调用错误回调无法正确接收HttpErrorResponse,测试时err输出为空字符串,导致foo未被设为true,测试失败。生产环境代码运行正常。
相关代码
component.ts
public thingThatCallsService() { this.foo = false; this.service.bar() .subscribe( (res) => {log(res)}, (err) => { log(err) // 测试期间输出空字符串 if (err.status === 400) this.foo = true; } ); }
mockService.ts(测试用模拟服务)
public bar() { return of(new HttpResponse()); }
test.ts
it("sets foo to true if bar returns an error", fakeAsync(() => { spyOn(service, "bar").and.returnValue( throwError(() => new HttpErrorResponse({status: 400})) ); component.thingThatCallsService(); tick(); componentFixture.detectChanges(); expect(service.bar).toHaveBeenCalled(); expect(component.foo).toBeTrue(); // 测试失败 }))
解决方案
1. 对齐RxJS版本的throwError用法
- RxJS 7+:工厂函数写法正确,但需确保导入的
throwError来自rxjs - RxJS 6及以下:直接传入错误对象,无需工厂函数:
throwError(new HttpErrorResponse({status: 400}))
2. 验证Spy的返回值
在测试中添加临时订阅,确认Spy返回的Observable确实抛出正确的错误:
const spy = spyOn(service, "bar").and.returnValue( throwError(() => new HttpErrorResponse({status: 400})) ); // 临时订阅验证错误 spy.calls.mostRecent().returnValue.subscribe({ error: err => console.log(err.status) // 应输出400 });
3. 完善HttpErrorResponse构造参数
补充必要字段,避免对象序列化异常:
throwError(() => new HttpErrorResponse({ status: 400, statusText: 'Bad Request', error: { message: 'Invalid input' }, url: '/api/bar' }))
4. 使用defer确保错误在订阅时抛出
用defer包装错误流,确保Observable在订阅阶段才创建错误:
import { defer, throwError } from 'rxjs'; spyOn(service, "bar").and.returnValue( defer(() => throwError(() => new HttpErrorResponse({status: 400}))) );
5. 排查服务流中的错误吞掉情况
检查服务的bar方法是否包含catchError操作符,若有则错误会被拦截,无法传递到组件的订阅回调。
内容的提问来源于stack exchange,提问作者TechnicallyTrue
相关产品推荐
相关产品推荐

