使用转换器时,基于 fake_cloud_firestore 包的 Firestore 流测试失败

问题描述 投票:0回答:1

我正在尝试为 Dart 函数编写一个单元测试,该函数使用 fake_cloud_firestore 进行模拟返回 Firestore 流。当 fakeFirestore 实例返回 DocumentSnapshots 流时,它工作得很好,但当这些相同的 DocumentSnapshots 通过

map()
转换为实际对象时,它会失败。

我尝试了很多emitLater、stream.take(3)、删除对象以强制关闭流等等的组合。没有区别。

如果

emitsInOrder([...]]
包含多个元素,第二个测试总是挂起。如果列表中的 first 元素不匹配,它可能会报告错误,但如果有其他元素,它仍然会挂起。

我认为这表明使用 map() 会导致打开流后应该出现的更新被忽略。有没有办法让这个测试继续工作,或者 fake_cloud_firestore 是一个死胡同?

import 'package:equatable/equatable.dart';
import 'package:fake_cloud_firestore/fake_cloud_firestore.dart';
import 'package:flutter_test/flutter_test.dart';

import 'document_snapshot_matcher.dart';

// Model class used in the second test
class User extends Equatable {
  final String name;
  final String other;

  const User({required this.name, required this.other});

  @override
  List<Object?> get props => [name, other];

  @override
  bool get stringify => true;

  factory User.fromMap(Map<dynamic, dynamic> map) {
    return User(name: map['name'], other: map['other']);
  }

  Map<String, dynamic> toMap() {
    return {'name': name, 'other': other};
  }

  User copyWith({String? name, String? other}) {
    return User(name: name ?? this.name, other: other ?? this.other);
  }
}

void main() {
  group('Demo Only', () {});

  //This is one of the tests from the fake_cloud_firestore package.
  // https://github.com/atn832/fake_cloud_firestore/blob/master/test/fake_cloud_firestore_test.dart
  // It finishes and passes as expected.
  test('Snapshots returns a Stream of Snapshot', () async {
    final uid = 'abc';
    final instance = FakeFirebaseFirestore();
    expect(
        instance.collection('users').doc(uid).snapshots(),
        emitsInOrder([
          DocumentSnapshotMatcher('abc', null),
          DocumentSnapshotMatcher('abc', {
            'name': 'Bob',
          }),
          DocumentSnapshotMatcher('abc', {
            'name': 'Frank',
          }),
        ]));
    await instance.collection('users').doc(uid).set({
      'name': 'Bob',
    });
    await instance.collection('users').doc(uid).update({
      'name': 'Frank',
    });
  });

  // This is the same test but this time the individual DocumentSnapshots
  // are converted into User objects.
  // This test works as expected when the list passed to emitsInOrder only has
  // one element but it hangs indefinitely if the list has more elements.
  test('Returns a stream of user objects, hangs', () async {
    final uid = 'abc';
    final instance = FakeFirebaseFirestore();

    expect(
        instance
            .collection('users')
            .doc(uid)
            .withConverter<User>(
              fromFirestore: (snapshot, _) => User.fromMap(snapshot.data()!),
              toFirestore: (user, _) => user.toMap(),
            )
            .snapshots()
            .map((snapshot) => snapshot.data()),
        emitsInOrder([
          null,
          User(name: 'Bob', other: 'initial object'),
          User(name: 'Frank', other: 'modified object'),
        ]));

    await instance.collection('users').doc(uid).set({
      'name': 'Bob',
      'other': 'initial object',
    });
    await instance.collection('users').doc(uid).update({
      'name': 'Frank',
      'other': 'modified object',
    });
  });
}
flutter unit-testing google-cloud-firestore mocking
1个回答
0
投票

看来我的测试没有什么问题。相反,模拟包并不能很好地替代原始包。

https://github.com/atn832/fake_cloud_firestore/pull/295

这个问题给了我一个至关重要的提示。如果使用转换器打开流,则所有后续操作也将需要转换器,否则它们将被忽略。

通过向我的设置和更新请求添加无用的转换器,我能够完成并通过测试。好悲伤。

await instance
    .collection('users')
    .doc(uid)
    .withConverter<User>(
      fromFirestore: (snapshot, _) => User.fromMap(snapshot.data()!),
      toFirestore: (user, _) => user.toMap(),
    )
    .set(User(name: 'Bob', other: 'initial object'));
await instance
    .collection('users')
    .doc(uid)
    .withConverter<User>(
      fromFirestore: (snapshot, _) => User.fromMap(snapshot.data()!),
      toFirestore: (user, _) => user.toMap(),
    )
    .update({
  'name': 'Frank',
  'other': 'modified object',
});
© www.soinside.com 2019 - 2024. All rights reserved.