【问题标题】:Flutter unit testing streams that do map进行映射的 Flutter 单元测试流
【发布时间】:2022-01-13 05:07:10
【问题描述】:

我确实坚持在返回值之前进行一些转换的测试流。我使用 Firestore 作为我的数据存储,并有一个单独的数据层执行从 DocumentSnapshot<T> 到我的模型的一些映射。这是一个 repo 的例子:

class RequestsRepository {
  final CollectionReference<Request> _requestsCollection =
      getIt<FirebaseFirestore>().collection('requests').withConverter<Request>(
          fromFirestore: (snapshot, _) => Request.fromJson(snapshot.data()!),
          toFirestore: (request, _) => request.toJson());

  Stream<Request?> observe(String id) {
    return _requestsCollection
        .doc(id)
        .snapshots()
        .map((snapshot) => snapshot.exists ? snapshot.data() : null);
    });
  }
}

现在我想用测试来介绍observe(id) 函数。这是我找到的解决方案,下面我将解释原因:

test('request exists', () async {
      // WHEN
      final stream = repository.observe(request.id);

      // expected events
      final events = [null, request, request..completed = true, null];
      var eventIndex = 0;

      // THEN
      stream.listen(expectAsync1((value) async {
        await Future.delayed(Duration(milliseconds: 100));
        expect(value, events[eventIndex]);
        eventIndex++;
      }, max: -1));

      // GIVEN
      await firestore
          .collection('requests')
          .doc(request.id)
          .set(request.toJson());

      request.completed = true;

      await firestore
          .collection('requests')
          .doc(request.id)
          .set(request.toJson());

      // reset request data
      request.completed = false;
    });

我尝试了emitsInOrder 流匹配器,但它失败了,因为我在observe(id) 函数内部进行映射,结果实际上不是request 对象而是_MapStream&lt;DocumentSnapshot&lt;Request?&gt;, Request?&gt;,而是因为流映射函数遵循的逻辑:

Stream<S> map<S>(S convert(T event)) {
    return new _MapStream<T, S>(this, convert);
  }

我来的解决方案确实适用于这个案例,但它不适用于其他测试,而且解决方案很臭。有什么建议如何测试这些流?

更新:

@pskink 的每条评论是演示测试失败,原因相同:

class Test {
  Stream<B> observe() {
    return Stream.periodic(Duration(milliseconds: 500), (i) => A(i * 10))
        .map((i) => B('s${i.a}'));
  }
}

class A {
  final int a;
  A(this.a);

  bool operator ==(o) => o is A && a == o.a;
  int get hashCode => a.hashCode;
}

class B {
  final String b;
  B(this.b);

  bool operator ==(o) => o is B && b == o.b;
  int get hashCode => b.hashCode;
}

void main() {
  test('mapped stream: A > B', () async {
    final stream = Test().observe();
    expect(stream, emitsInOrder([B('s0'), B('s10'), B('s20'), B('s30')]));
  });
}

到目前为止,它通过了测试。

【问题讨论】:

  • 发布一个可以轻松复制的短代码 sn-p(没有任何 Firestore 部门),例如:test('mapped stream: int &gt; String', () async { final stream = Stream.periodic(Duration(milliseconds: 500), (i) =&gt; i * 10) .take(4) .map((i) =&gt; 's$i'); expect(stream, emitsInOrder(['s0', 's10', 's20', 's30'])); }); - 这里 Stream&lt;int&gt;Stream.map()ed 到 Stream&lt;String&gt; 和测试通过了
  • @pskink 是的,对不起,我的错误。所以我更新了测试以接近我所看到的,并且看起来短代码 sn-p 工作正常。

标签: flutter testing flutter-test


【解决方案1】:

感谢@pskink 到目前为止确定问题不在于流转换(即使日志看起来很不可读)。我必须让我的 Request 对象 Equatable 以便它现在可以适当地比较所有字段。而且我必须从firestore 调用中删除await,以便事件真正异步发生。

这是一个工作测试的例子:

test('request exists', () async {
      // GIVEN
      final timestamp = DateTime.now();
      final request = Request(
          '49a257e1-c0e3-4cc1-9053-aaf55197f897',
          user.id,
          "${user.firstName} ${user.lastName}",
          user.phone ?? "",
          'center',
          'comment',
          timestamp,
          false,
          false);

      await firestore
          .collection('requests')
          .doc(request.id)
          .set(request.toJson());

      // WHEN
      final stream = repository.observe('id', request.id);

      // THEN
      expect(
          stream,
          emitsInOrder([
            Request(
                '49a257e1-c0e3-4cc1-9053-aaf55197f897',
                user.id,
                "${user.firstName} ${user.lastName}",
                user.phone ?? "",
                'center',
                'comment',
                timestamp,
                false,
                false),
            Request(
                '49a257e1-c0e3-4cc1-9053-aaf55197f897',
                user.id,
                "${user.firstName} ${user.lastName}",
                user.phone ?? "",
                'center',
                'comment',
                timestamp,
                false,
                true),
          ]));

      firestore
          .collection('requests')
          .doc(request.id)
          .set({"completed": true}, SetOptions(merge: true));
    });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-18
    • 1970-01-01
    相关资源
    最近更新 更多