【问题标题】:How to test a private function, in Dart?如何在 Dart 中测试私有函数?
【发布时间】:2014-03-06 14:38:34
【问题描述】:

假设我在 dart 文件 hello.dart 中定义了一个私有函数:

_hello() {
  return "world";
}

我想在另一个文件中测试它mytest.dart

library mytest;

import 'dart:unittest/unittest.dart';

main() {
  test('test private functions', () {
    expect(_hello(), equals("world"));
  }
}

但很遗憾,无法编译测试代码。但我确实需要测试那个私有的_hello 函数。有什么解决办法吗?

【问题讨论】:

标签: dart dart-unittest


【解决方案1】:

虽然我同意私有方法/类不应成为您的测试的一部分,但元数据包确实提供了一个 @visibleForTesting 属性,如果您尝试在其原始成员之外使用该成员,分析器会向您发出警告图书馆或测试。你可以这样使用它:

import 'package:meta/meta.dart';

@visibleForTesting
String hello() {
  return "world";
}

您的测试现在可以在没有错误或警告的情况下使用它,但如果其他人尝试使用它,他们会收到警告。

同样,关于这样做是否明智是另一个问题 - 通常,如果它是值得测试的东西,它就是值得公开的东西(或者它会通过你的公共接口进行测试,这才是真正重要的)。同时,您可能只想对您的私有方法/类进行严格的测试或测试驱动原则,所以 - Dart 让您这样做。

编辑添加:如果您正在开发一个库并且您的带有@visibleForTesting 的文件将被导出,那么您实际上是在添加公共 API。有人可以在关闭分析器的情况下使用它(或者只是忽略警告),如果您稍后将其删除,您可能会破坏它们。

【讨论】:

  • 对不起,但我不同意“值得测试的东西值得公开”的说法。按照这种逻辑,没有任何获取、映射、处理等方法值得测试,因为在大多数情况下,没有理由将它们公开。但这意味着,我必须运行 90% 的“公共”代码才能测试一个嵌套的私有方法,我什至可能无法直接验证其结果,因为它在途中被丢弃了。直接测试该私有方法似乎比通过评估其间接影响来确定它是否正常工作更有效。
  • IME,这样的函数通常值得封装在自己的类中,因此可以在其他测试中单独测试或适当地模拟它们。
  • 它适用于类和构造函数参数吗?是的,我试过了,我仍然可以使用带有该注释的构造函数参数,但也许我做错了
  • 是的,确实如此,例如class Foo { Foo({@visibleForTesting this.someInt = 42}; final int someInt; }
【解决方案2】:

一些人认为我们不应该直接测试私有:它应该通过公共接口进行测试。

遵循本指南的一个优点是您的测试将不依赖于您的实施。换种说法:如果你想改变你的私人而不改变你暴露给世界的东西,那么你就不必碰你的测试。

不过,根据这所学校的说法,如果您的 private 足够重要以证明单元测试的合理性,那么将它提取到一个新类中可能是有意义的。

将所有这些放在一起,您可以在这里做的是:

  • 用这个hello公开的方法创建一个帮助类。然后,您可以轻松地对其进行单元测试
  • 让您当前的类使用此帮助类的实例
  • 测试依赖于_hello 的当前类的公共方法:如果此私有有错误,则应该被那些更高级别的测试捕获

【讨论】:

  • 您的建议很有道理,但它看起来适用于所有语言。它也是 Dart 的最佳解决方案吗?
  • 如你所料,我的回答不是 Dart 特有的。
  • 我被严格的语言封装所强迫(就像我们大多数人一样),我不认为这是一个足够的理由,因为私有方法会变得混乱、复杂、递归,等等。所以对于 OP,我建议你确实将这些东西提取到一个新类中,并为重复的样板保留私有内容(当然,直到你遇到这条规则的例外情况)。这将是一个很好的机会,可以让您的代码通用、抽象并满足我们在编写高质量代码时都喜欢的所有最佳实践。
  • 我讨厌这所学校,我还需要测试私有方法
  • 是的,出于同样的原因,我没有测试任何后端代码。这只是一个实现细节,公共 UI 才是最重要的。如果我想测试它,我会把它移到前端代码中。这样我也可以在不更新任何测试的情况下更改我的后端实现。没有人最终会写出太复杂的东西,以至于应该在任何私有方法中进行测试……我的意思是后端代码。
【解决方案3】:

建议将方法/类设为私有,而是将要隐藏实现细节的代码移动到 lib/src 文件夹。 此文件夹被视为私有文件夹。
我在 fuchsia.dev 页面 this section 的“测试”下找到了这种方法。

如果您想向公众公开位于 src 文件夹中的那些私有方法/类,您可以将它们导出到您的 lib/main 文件中。

我尝试将我的一个库 A(项目是库)导入另一个库 B,但无法导入库 A 的 src 文件夹中的代码。 根据StackOverflow answer,仍然可以从库 B 中的 A 访问 src 文件夹。

来自dart documentation

如您所料,库代码位于 lib 目录下,并且对其他包是公开的。您可以根据需要在 lib 下创建任何层次结构。按照惯例,实现代码放在 lib/src 下。 lib/src 下的代码被认为是私有的;其他包应该永远不需要导入 src/.... 要将 lib/src 下的 API 公开,您可以从 lib 直接下的文件中导出 lib/src 文件。

【讨论】:

  • 您建议的方法是正确的。但是src 中的代码是包私有的(在 Dart 中,单词库用于指代单个 .dart 文件——更准确地说是那些没有指令部分的文件)是约定,而不是约束。也许在您看来这是一个限制,因为 IDE(如 IntelliJ 或 Android Studio)尊重它,所以他们不建议导入这些文件,但可以手动编写导入,您将能够编译和执行代码.
猜你喜欢
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 2011-08-07
  • 2020-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多