Dart中如何按顺序断言Stream取消前发射的所有数据项?
如何严格按顺序断言Stream发射的全部数据项
问题描述
需要找到便捷方法,按顺序断言Stream被取消前发射的所有数据项,不能遗漏多余的发射事件。
直接使用emitsInOrder的常规写法存在缺陷:
expectLater( stream, emitsInOrder(<String>[ 'item1', 'item2', ]), );
当被测试的Stream实际发射序列为['item1', 'item2', 'item3']时,测试不会失败,无法识别多余的发射项。
目前可通过手动计数的方式实现严格校验:
var count = 0; final expected = ['item1', 'item2', 'item3']; stream.listen( expectAsync1( (final result) { expect(result, expected[count++]); }, count: expected.length, ), );
但这种写法冗长、可读性差,有更简洁优雅的实现方案。
方案1:直接使用emitsExactly匹配器
Dart官方test包内置的emitsExactly就是为全量严格匹配Stream设计的匹配器,特性如下:
- 事件顺序必须和传入列表完全一致
- 不允许存在列表外的多余发射项
- 匹配完所有给出的项后,要求Stream正常结束,无后续事件
- 断言失败时会输出清晰的差异信息,明确标注缺失/多余事件的位置和内容
写法和emitsInOrder完全一致,不需要手动编写监听、计数逻辑:
expectLater( stream, emitsExactly(<String>[ 'item1', 'item2', ]), );
如果此时Stream额外发射了item3,测试会直接失败,满足严格校验的需求。如果需要匹配带条件的事件,也可以在列表中传入Matcher对象而非具体值,用法和emitsInOrder完全兼容。
方案2:emitsInOrder搭配emitsDone
如果需要基于emitsInOrder实现严格匹配,只需要在匹配列表末尾追加emitsDone匹配器,效果和emitsExactly一致:
expectLater( stream, emitsInOrder(<Matcher>[ 'item1', 'item2', emitsDone, // 校验匹配完所有项后Stream立刻结束,无多余事件 ]), );
注意:列表类型需要声明为
Matcher,因为emitsDone是Matcher类型,和字符串值混用时需要统一类型。
两种官方方案都可以完全替代手动计数监听的写法,代码更简洁,报错定位更高效。
内容的提问来源于stack exchange,提问作者David Miguel
相关产品推荐
相关产品推荐

