如何在Dart中测试流

如何在Dart中测试流,dart,reactive-programming,Dart,Reactive Programming,如何在dart中测试流?我有以下代码: test('单词按顺序正确读取',(){ WordTrackerInterface wordTracker=wordTracker.byContent('0 1 2'); setWordScontPerchunk(1); var stream=wordTracker.nextWordStringStream(); 期待( 流动 emitsInOrder(List.generate( 6,(i)=>i>2?单词(“”):单词(i.toString()); 对

如何在dart中测试流?我有以下代码:

test('单词按顺序正确读取',(){
WordTrackerInterface wordTracker=wordTracker.byContent('0 1 2');
setWordScontPerchunk(1);
var stream=wordTracker.nextWordStringStream();
期待(
流动
emitsInOrder(List.generate(
6,(i)=>i>2?单词(“”):单词(i.toString());
对于(int i=0;i<6;i++){
wordTracker.nextWord();
}
});
我需要测试成员数据
Word::content
,它是
字符串
,是否与
emitsInOrder
中提供的数据相同

类似于流的以下内容:

expect(
流动
emitsInOrder(List.generate(
6,(i)=>i>2?单词(“”):单词(i.toString()),
expect((实际单词,预期单词){
返回实际的.content==预期的.content;
}));

尝试使用
async
/
wait
expectLater

test('words are reading sequentially correct', () async {
  WordTrackerInterface wordTracker = WordTracker.byContent('0 1 2');
  wordTracker.setWordsCountPerChunk(1);
  var stream = wordTracker.nextWordStringStream();

  await expectLater(
      stream,
      emitsInOrder(List<Word>.generate(
          6, (i) => i > 2 ? Word('') : Word(i.toString()))));

  for (int i = 0; i < 6; i++) {
    wordTracker.nextWord();
  }
});
test('字按顺序读取正确',()异步{
WordTrackerInterface wordTracker=wordTracker.byContent('0 1 2');
setWordScontPerchunk(1);
var stream=wordTracker.nextWordStringStream();
待会儿(
流动
emitsInOrder(List.generate(
6,(i)=>i>2?单词(“”):单词(i.toString());
对于(int i=0;i<6;i++){
wordTracker.nextWord();
}
});

在阅读了dart文件中的源代码并在互联网上阅读之后,我找到了解决方案:我需要创建一个自定义匹配器。我在笔记本电脑上测试了以下代码,并引用了我的应用程序中的其他文件,如“WordTracker”,代码按预期运行

test('words are reading sequentially correct', () {
    WordTrackerInterface wordTracker = WordTracker.byContent('0 1 2');
    wordTracker.setWordsCountPerChunk(1);
    var stream = wordTracker.nextWordStringStream();

    expect(stream, 
      emitsInOrder(List<Word>.generate(6, (i) => i > 2 ? Word('') : Word(i.toString())).map<WordMatcher>(
        (Word value) => WordMatcher(value))));

    for (int i = 0; i < 6; i++) {
      wordTracker.nextWord();
    }
  });


class WordMatcher extends Matcher {
  Word expected;
  Word actual;
  WordMatcher(this.expected);

  @override
  Description describe(Description description) {
    return description.add("has expected word content = '${expected.content}'");
  }

  @override
  Description describeMismatch(
    dynamic item,
    Description mismatchDescription,
    Map<dynamic, dynamic> matchState,
    bool verbose
  ) {
    return mismatchDescription.add("has actual emitted word content = '${matchState['actual'].content}'");
  }

  @override
  bool matches(actual, Map matchState) {
    this.actual = actual;
    matchState['actual'] = actual is Word ? actual : Word('unknown');
    return (actual as Word).content == expected.content;
  }
}
test('单词按顺序正确读取',(){
WordTrackerInterface wordTracker=wordTracker.byContent('0 1 2');
setWordScontPerchunk(1);
var stream=wordTracker.nextWordStringStream();
期望(流),
emitsInOrder(List.generate(6,(i)=>i>2?Word(“”):Word(i.toString()).map(
(单词值)=>WordMatcher(值));
对于(int i=0;i<6;i++){
wordTracker.nextWord();
}
});
类WordMatcher扩展了Matcher{
期望词;
字实际;
WordMatcher(this.expected);
@凌驾
描述(描述){
返回description.add(“has expected word content='${expected.content}'”;
}
@凌驾
描述不匹配(
动态项,
描述不匹配描述,
地图匹配状态,
冗长的
) {
返回mistchdescription.add(“has实际发出的单词内容='${matchState['actual'].content}'”);
}
@凌驾
布尔匹配(实际、映射匹配状态){
this.actual=实际;
matchState['actual']=actual是单词?actual:单词('unknown');
return(实际为Word).content==expected.content;
}
}

如果流正在发射具有要测试的属性的对象,
expectAsync1
可以帮助:

List<Record> expectedRecords = [record1, record2, record3];
int i = 0;
recordStream.listen(
    expectAsync1<void,Record>(
    (record) {
      expect(record.name, expectedRecords[i].name);
      i++;
    }, 
    max: -1)
);

每次流
recordStream
发出
记录时,都会运行该命令

expectAsync1
中的
1
是所包含函数将接受的参数数。通常情况下,这是1
(记录)
是上面的一个参数

对于上面的示例,
expectAsync1
具有(可选)类型参数:
第二个类型参数
Record
告诉封闭函数发出的流项属于
Record
类型,允许我使用类似
Record.name
的属性,而无需强制转换

第一个类型参数是封闭函数的返回类型。我使用了
void
,因为所包含的函数没有返回任何内容,它只是运行一个
expect
匹配器并迭代一个计数器,该计数器用于迭代我希望看到的
记录列表(即
expectedRecords

最大参数 您会注意到所附函数下方的
max:-1
。这是
expectAsync1
的一个可选但重要的参数,用于指定我们期望的流项目/事件的数量

如果未给出
max
,则默认为
1
,如果发出超过1个事件,则测试将失败

错误将被
回调调用的次数超过预期次数(1)。

在上面的示例中,我使用了
-1
,这意味着可以发出/测试无限的事件。如果要测试从流中获得的项目/事件的数量,可以指定一个非零数,否则测试将失败。我可以在上面的例子中使用
max:3

RxDart 如果您使用的是RxDart
BehaviorSubject
请记住,最近的流事件是在
listen
时发出的。因此,在测试中,当您开始侦听/使用
expectAsync1
时,将立即调用包含最近事件的函数


ReplaySubject
将在
listen

嗨@Kevin,谢谢你的回答,但是你提供的并没有回答我的问题。我想在emitsInOrder内部检查从流中发出的内容是否为Word(object),以及类型为“String”的字段“content”是否与列表中提供的“String”相同。生成方法如下(此代码是假设的):expect(流,emitsInOrder(List.generate)(6,(I)=>I>2?Word(“”):Word(i.toString()),(Word-actual,Word-expected){return-actual.content==expected.content;});
    (record) {
      expect(record.name, expectedRecords[i].name);
      i++;
    }