如何为combineLatest Observable编写大理石测试?解决测试报错
Jasmine-Marbles测试Observable时的Notification类型错误排查与修复
问题场景
我实现了一个LoadingService,通过RxJS的combineLatest合并两个Observable<boolean>,并对执行结果做逻辑或操作:
interface LoadingEventEmitter { isLoading$: Observable<boolean> } export class LoadingService { isLoading$: Observable<boolean>; constructor( private requests: LoadingEventEmitter, private lazyRoutes: LoadingEventEmitter ) { this.isLoading$ = combineLatest([ this.requests.isLoading$, this.lazyRoutes.isLoading$, ]).pipe( map( ([requestsLoading, lazyRoutesLoading]) => requestsLoading || lazyRoutesLoading ) ); } }
为验证逻辑正确性,我用jasmine-marbles编写了测试用例,但测试执行失败:
fdescribe('LoadingService', () => { const createLoadingService = ( requests$: Observable<boolean>, lazyLoading$: Observable<boolean> ) => { const mockRequests = { isLoading$: requests$ }; const mockLazyLoading = { isLoading$: lazyLoading$ }; return new LoadingService(mockRequests, mockLazyLoading); }; const values = { t: true, f: false }; it('isLoading$ should be true when at least one of the sources emits true', () => { const a = cold('---t---f---f---', values); // First source const b = cold('f----t---------', values); // Second source const c = cold('---t-t-t---t---', values); // Result const service = createLoadingService(a, b); expect(service.isLoading$).toBeObservable(c); }); });
错误信息
测试抛出如下类型不匹配错误:
Expected $[0].notification to be a kind of Notification, but was Object({ kind: 'N', value: true, error: undefined }). Expected $[1].notification to be a kind of Notification, but was Object({ kind: 'N', value: true, error: undefined }). Expected $[2].notification to be a kind of Notification, but was Object({ kind: 'N', value: true, error: undefined }). Expected $[3].notification to be a kind of Notification, but was Object({ kind: 'N', value: true, error: undefined }).
错误含义
这个错误核心原因是jasmine-marbles与RxJS版本不兼容:
- 早期版本的jasmine-marbles依赖RxJS内置的
Notification类包装事件通知 - 适配RxJS 7+的新版本jasmine-marbles,改用普通JavaScript对象(格式为
{ kind: 'N', value: ... })表示通知 - 测试环境中,
toBeObservable断言期望接收RxJS的Notification实例,但实际从Observable得到的是普通对象,因此触发类型不匹配错误。
修复方案
方案1:升级jasmine-marbles到兼容版本
如果项目使用RxJS 7及以上版本,直接升级jasmine-marbles到最新兼容版本即可解决问题:
npm install jasmine-marbles@latest --save-dev
升级后原有测试代码无需修改,断言会自动适配新的通知格式。
方案2:手动转换通知格式(适用于无法升级依赖的场景)
通过RxJS的materialize()操作符,将Observable事件流转换为标准通知流,确保断言双方格式一致:
- 导入
materialize操作符:
import { materialize } from 'rxjs/operators';
- 修改测试中的断言逻辑:
it('isLoading$ should be true when at least one of the sources emits true', () => { const a = cold('---t---f---f---', values); const b = cold('f----t---------', values); const c = cold('---t-t-t---t---', values); const service = createLoadingService(a, b); // 同时转换实际流和预期流为通知格式 expect(service.isLoading$.pipe(materialize())).toBeObservable(c.pipe(materialize())); });
内容的提问来源于stack exchange,提问作者Allan Juan
相关产品推荐
相关产品推荐

