Flutter 测试中的插件
在 Flutter 测试中添加插件。
几乎所有的 Flutter 插件都包含两个部分:
- Dart 代码,提供您代码所调用的 API。
- 使用特定平台(或“宿主”)语言(如 Kotlin 或 Swift)编写的代码,用于实现这些 API。
事实上,正是这些原生(或宿主)语言代码将插件包与标准包区分开来。
构建和注册插件的宿主部分是 Flutter 应用构建过程的一部分,因此插件仅在您的代码于应用中运行时有效,例如使用 flutter run 或运行 集成测试 时。当运行 Dart 单元测试 或 组件测试(Widget tests) 时,宿主代码是不可用的。如果您正在测试的代码调用了任何插件,通常会导致以下错误:
MissingPluginException(No implementation found for method someMethodName on channel some_channel_name)
在对使用插件的代码进行单元测试时,有几种方法可以避免此异常。以下解决方案按推荐程度排序。
封装插件
#在大多数情况下,最好的方法是将插件调用封装在您自己的 API 中,并提供一种在测试中模拟(mocking)您自己 API 的方法。
这样做有几个优点:
- 如果插件 API 发生变化,您无需更新测试。
- 您只需测试自己的代码,因此测试不会因为所使用插件的行为而失败。
- 无论插件如何实现,甚至对于非插件包依赖项,您都可以使用相同的方法。
模拟插件的公共 API
#如果插件的 API 已经基于类实例,您可以直接对其进行模拟,但需注意以下事项:
- 如果插件使用非类函数或静态方法,此方法将无效。
- 当插件 API 发生变化时,测试将需要更新。
模拟插件的平台接口
#如果该插件是联合插件(federated plugin),它将包含一个平台接口,允许注册其内部逻辑的实现。您可以注册该平台接口实现的模拟,而不是模拟公共 API,但需注意以下事项:
- 如果插件不是联合插件,此方法将无效。
- 您的测试将包含插件代码的一部分,因此插件的行为可能会给测试带来问题。例如,如果插件作为内部缓存的一部分写入文件,您的测试行为可能会根据之前是否运行过测试而改变。
- 当平台接口发生变化时,测试可能需要更新。
在某些情况下(例如模拟您所依赖的包所使用的插件实现,而非您自己的代码),您可能不得不使用此方法,因为您无法更改其调用方式。但是,如果可能的话,您应该模拟使用该插件的依赖项。
模拟平台通道
#如果插件使用平台通道,您可以使用 TestDefaultBinaryMessenger 来模拟平台通道。除非出于某种原因上述方法均不可用,否则才应使用此方法,因为它有几个缺点:
- 只能模拟使用平台通道的实现。这意味着如果某些实现不使用平台通道,您的测试在某些平台上运行时将意外地使用真实实现。
- 平台通道通常是插件的内部实现细节。即使在插件的漏洞修复更新中,它们也可能发生重大变化,从而意外导致您的测试失败。
- 联合插件的每个实现中的平台通道可能不同。例如,您可能设置了模拟平台通道以使测试在 Windows 机器上通过,却发现它们在 macOS 或 Linux 上运行时失败了。
- 平台通道不是强类型的。例如,方法通道通常使用字典,您必须阅读插件的实现代码才能知道键字符串和值类型是什么。
由于这些限制,TestDefaultBinaryMessenger 主要用于插件实现本身的内部测试,而不是用于测试使用插件的代码。
您可能还需要查看测试插件。