使用Promise的mergeMap大理石测试无输出问题排查
解决RxJS TestScheduler测试Promise转换无输出的问题
我来帮你排查并解决这个测试无输出的问题,主要有几个关键点需要调整:
核心问题分析
你的测试没有输出,大概率是因为缺少触发TestScheduler执行的关键步骤,再加上Promise的异步特性和TestScheduler的同步模拟机制不兼容,导致断言没有正确执行。
完整修复后的测试代码
import { TestScheduler } from 'rxjs/testing/TestScheduler'; import 'rxjs/add/operator/mergeMap'; // 注意:你用了mergeMap,要导入对应的操作符 import { expect } from 'chai'; describe('Observable转Promise的测试', () => { it('应该正确发射Promise解析后的值', async () => { // 初始化TestScheduler,用chai的deep.equal做对比 const marbles = new TestScheduler((actual, expected) => { expect(actual).to.deep.equal(expected); }); // 定义marble字符对应的实际值(避免undefined) const testValues = { a: 'sample-value' }; // 创建Cold Observable,每10帧发射一次'a'(默认每个marble字符代表10帧) const source$ = marbles.createColdObservable('a-a-a-a', testValues); // 应用mergeMap转换为Promise(这里模拟异步操作) const mapped$ = source$.mergeMap(async (val) => { // 模拟真实场景中的异步逻辑,比如API请求 await new Promise(resolve => setTimeout(resolve, 0)); return val; }); // 预期输出:因为Promise是微任务,会比原Observable晚一帧发射,所以用'-a-a-a-a' marbles.expectObservable(mapped$).toBe('-a-a-a-a', testValues); // 关键:触发TestScheduler执行所有模拟时间的操作 marbles.flush(); // 等待所有微任务完成(Promise的resolve会进入微任务队列) await Promise.resolve(); }); });
关键调整点说明
- 导入正确的操作符:你代码里用了
mergeMap,但导入的是mergeAll,这会导致操作符未生效,必须改成import 'rxjs/add/operator/mergeMap'。 - 调用
flush():TestScheduler是同步模拟时间的,必须调用marbles.flush()才会让Observable开始发射值,没有这一步测试完全不会执行。 - 处理Promise的异步特性:Promise的
resolve会进入微任务队列,而TestScheduler的flush()是同步执行的,所以需要在flush()后用await Promise.resolve()等待所有微任务完成,确保断言时Promise已经解析。 - 指定marble对应的值:
createColdObservable的第二个参数用来映射marble字符到实际值,避免发射undefined,让断言更准确。 - 调整预期的marble图:因为Promise解析有微任务延迟,预期的发射时间会比原Observable晚一帧,所以用
-a-a-a-a而不是和源一样的a-a-a-a。
额外提示
如果你的异步操作有实际延迟(比如API请求需要50ms),可以在marble图中模拟对应的时间,比如需要20帧完成的话,预期marble就写成--a--a--a--a,每个-代表10帧,这样测试会更贴合真实场景。
内容的提问来源于stack exchange,提问作者Aleksandar Dimitrov
相关产品推荐
相关产品推荐

