Flutter Firebase 函数的单元测试

Posted

技术标签:

【中文标题】Flutter Firebase 函数的单元测试【英文标题】:Unit Testing On Flutter Firebase functions 【发布时间】:2019-04-13 00:40:54 【问题描述】:

美好的一天,我正在尝试对以下在 Cloud Firestore 中创建文档的函数执行一些单元测试。我在我的应用程序中使用了一个函数,它创建了一个文档,但我想编写一个 test.dart 文件,该文件对以下函数执行单元测试,甚至在控制台上打印一些输出以进行验证。

我认为我没有以正确的方式编写我的 Test.dart。我收到一个错误。

createdatabase.dart 文件中的函数

Future<dynamic> createDoc(dataMap,collection) async 
  final TransactionHandler createTransaction = (Transaction tx) async 
    final DocumentSnapshot ds = await tx.get(db.collection(collection).document());
    final Map<String, dynamic> result = ;
    result.addAll(dataMap);
    result['id'] = ds.documentID;
    await tx.set(ds.reference, result);

    return result;
  ;

Test.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:test/test.dart';
import '../lib/service/createfirebase.dart';

void main() 
  CreateFirebase cf = new CreateFirebase();   
   //test    
    test('Creating doc on firestore ', () async 
      Object dataObj ='name':'Dev','title':'Dev';
      var create = await cf.createDoc(dataObj, 'crude');
      expect(true,create);
      print('The doc details are');
      print(dataObj);
    );


运行此测试后的错误是 MissingPluginException(在通道 plugins.flutter.io/cloud_firestore 上找不到方法 Firestore#runTransaction 的实现)

但我不明白为什么,因为我拥有所有依赖项,并且如果我在另一个类中调用该函数,则会创建文档。但是在这个测试中调用会出现上述错误。我想我的做法不对。

我可以查看任何有助于测试此类功能的贡献或任何参考资料?

【问题讨论】:

据我了解,插件使用平台特定代码运行,这意味着如果它在 android 上运行,它将运行 Java/Kotlin 代码。在内部测试中,它不会有任何平台代码可以运行。这使您可以选择在 Firestore 中使用 driver test 或 mock。 【参考方案1】:

TLDR:mazei513 的评论是正确的。由于 Flutter Firestore 是一个插件而不是一个包,它需要一个平台来运行。例如,该平台可以是 ios 手机或 Android 虚拟设备。因此,您不能编写 unit 测试来测试 Firestore 命令。您必须使用integration_test 包来执行此类测试。

了解插件与包之间的区别

正如doc 所说,一个插件

是一种特殊的包,它使平台功能 可用于应用程序。可以为 Android 编写插件包 (使用 Kotlin 或 Java)、iOS(使用 Swift 或 Objective-C)、web、macOS、 Windows、Linux 或其任意组合。

如果您查看 /usr/local/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.7.0 中的 Firestore 插件,您会看到:

jjanvier:nouba$ ls -l /usr/local/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.7.0                                   
total 48
drwxr-xr-x 4 jjanvier jjanvier  4096 Oct  6 17:20 android
drwxr-xr-x 3 jjanvier jjanvier  4096 Oct  6 17:20 ios
drwxr-xr-x 3 jjanvier jjanvier  4096 Oct  6 17:20 lib
drwxr-xr-x 3 jjanvier jjanvier  4096 Oct  6 17:20 macos
-rw-r--r-- 1 jjanvier jjanvier   912 Oct  6 17:20 pubspec.yaml

由于 Firebase 插件实际上根据平台(Android、iOS、MacOS...)运行本机代码,因此它们需要在“真实”设备上运行。因此,它不适用于flutter test,它只是一个简单的 Dart 执行器。

测试 Firestore 存储库(或命令或查询)

关于设备模拟器

要获得一个可以运行测试的平台,您有多种选择。例如:

从您的 IDE 启动 Android 虚拟设备。这就是我在本地工作时所做的。 在您的持续集成管道上设置 Android 虚拟设备。例如,您 this one 用于 Github 操作。然后你可以在命令行中start the emulator。 使用Firebase Test Lab。我没有使用它,但它应该可以工作。

使用 integration_test

关注this documentation为您的项目配置integration_test。不要忘记使用testWidgets 而不是test,因为这样可以在设备模拟器而不是在 Dart 简单环境中启动测试。

完成后,所有集成/端到端测试都可以使用flutter test integration_test 启动。

不要弄乱你的生产数据库

如果您按原样启动命令flutter test integration_test,则测试中存在的文档'name':'Dev','title':'Dev' 很有可能会出现在您的生产数据库中。

为了解决这个问题,您主要有两种选择:

    设置一个用于测试的真实 Firebase 项目 使用Firebase local emulator suite

对于我的项目,我选择了第二个选项。只需一条命令,您就可以启动 Firebase 模拟器、加载设备并运行测试:

firebase --config="firebase.test.json" emulators:exec --import fixtures/ "flutter test integration_test/ --dart-define=FOO=bar"

让我们详细说明一下命令:

--config="firebase.test.json" 使用这个配置文件启动 firebase。这允许我在启动测试时保持本地模拟器套件运行 --import fixtures/:将文件夹“fixtures”加载为数据集 emulators:exec "flutter test integration_test/ --dart-define=FOO=bar":使用 FOO 环境变量启动集成测试

关于模拟/伪造 Firestore

我不建议您模拟或伪造 Firestore,因为这对您而言毫无意义。如果您想测试的是您实际上可以在 Firestore 中正确写入,那么在 Firestore 中使用双精度是没有意义的。

但是,在某些情况下它可能很有用。例如,对在某些时候写入或查询 Firestore 的业务行为进行单元测试。

同样,您有几种解决方案:

您可以自己模拟 Firestore,like it's done here。但是做 IMO 是相当复杂和痛苦的。 您可以使用包fake_cloud_firestore。顾名思义,这是一个完整的 Cloud Firestore 假货。到目前为止,一切都很好,非常适合我。

【讨论】:

【参考方案2】:

自从这个问题提交以来已经有一段时间了,但只是为了不让它没有回复。

当我偶然发现同样的错误时,我发现了这个有用的问题:https://github.com/flutter/flutter/issues/13971

基本上重新安装所有软件包:

flutter clean
flutter packages get

希望对你有帮助。

【讨论】:

以上是关于Flutter Firebase 函数的单元测试的主要内容,如果未能解决你的问题,请参考以下文章

如何从 firebase_auth 测试“signInWithEmailAndPassword”

如何使用 Firebase Cloud Firestore 对方法进行单元测试?

Flutter Firebase Functions:调用函数时出错

从 Flutter 应用通过本地网络连接到 Firebase 函数模拟器

Firebase + Flutter - 云函数 onCall 导致 Android 应用出现“未经身份验证”错误

如何从 Dart VM / Dart 集成测试访问 Firebase Firestore?