【问题标题】:When is a Test not a Unit-test?什么时候测试不是单元测试?
【发布时间】:2009-08-10 22:24:04
【问题描述】:

我正在寻找这样的规则:

如果满足以下条件,则测试不是单元测试:

  • 它与数据库通信
  • 它不能与其他测试并行运行
  • 使用注册表或文件系统等“环境”

还有什么?

【问题讨论】:

  • 除了上面所说的,检查一下:这个question
  • Roy Osherove 对单元测试的定义:只在内存中,运行速度快,可重复,不触及任何外部资源

标签: unit-testing


【解决方案1】:

Michael Feathers' definition

如果满足以下条件,则测试不是单元测试:

  • 它与数据库对话
  • 它通过网络进行通信
  • 涉及文件系统
  • 它不能与您的任何其他单元测试同时运行
  • 您必须对您的环境做一些特殊的事情(例如编辑 配置文件)来运行它。

【讨论】:

  • 当然不是。跨越多个层(例如业务逻辑、视图和控制器)的测试也不被视为单元测试。
  • 我不认为特征列表是定义概念的有用方法。它将理解减少到要记住的一堆规则和琐事。虽然初学者自然渴望规则 - 包括我自己,而且我是单元测试的初学者 - 从长远来看,专注于概念,为什么重要,然后尝试和思考它如何适合你自己的环境会更有效。所以当初学者询问规则时,关心的专家应该首先解释这个想法,然后列出一些例子。 :)
  • 单元测试的特征取决于我们正在测试的代码单元。如果您为数据库插入/选择编写 DaoTest,我们实际上是在对映射(在 ORM 的情况下)或与表结构相关的预期映射进行单元测试。我们实际上并没有测试 DB 或层,我们只测试我们在 DAO 中编写的代码单元。因此,如果它与数据库对话,它的通用声明是无效的。
  • -1 这个答案只是“教条”。一个更有用的定义将引导开发人员创建良好的、有用的自动化测试,而不是仅仅试图满足任意标准。尤其是涉及到文件系统这一点,鼓励开发人员尝试mock文件系统,而这在实践中通常很难做到;此外,IO 代码倾向于使用低级 API,因此该代码在很大程度上是特定于实现的;确实让测试touch(本地)文件系统要好得多。
  • @Rogério 关键是单元测试独立于其他任何东西。如果文件更改位置怎么办?模拟数据并不是那么糟糕。
【解决方案2】:

如果一个测试没有测试一个单元,它就不是一个单元测试。

说真的,仅此而已。

单元测试中“单元”的概念并没有很好的定义,事实上,到目前为止我找到的最好的定义实际上并不是一个定义,因为它是循环的:单元测试中的单元是最小的可能的东西可以单独测试。

这为您提供了两个检查点:是否单独测试?它是最小的吗?

请注意,这两者都取决于上下文。在一种情况下可能是最小的东西(例如,整个对象)在另一种情况下可能只是一个单一方法的一小部分。在一种情况下被视为隔离的可能在另一种情况下(例如,在内存管理的语言中,您永远与垃圾收集器隔离运行,而且大多数时候这无关紧要,但有时它可能不是)。

【讨论】:

  • +1 :非常好。当然和list Carl cites 一样有用
  • +1:我们都应该相互分享这种理解,而不是列表和规则——因为(a)它们充其量是典型的,而不是普遍的,并且(b)理解概念是唯一能让你知道什么时候打破规则的东西。
【解决方案3】:

困难的...

对我来说,单元测试在隔离中验证一个特定的逻辑。意思是,我采取一些逻辑,从其余部分中提取它(如果有必要通过模拟依赖项)并通过探索不同类型的可能控制流来测试该逻辑 - 一个(整体)单元。

但另一方面...我们可以总是 100% 说正确或不正确吗?不要成为哲学,而是 - 就像Michael says在他的帖子中一样:

执行these things 的测试还不错。 它们通常值得写,而且它们 可以写在单元测试工具中。 然而,重要的是能够 将它们与真正的单元测试分开,所以 我们可以保留一组测试 每当我们使我们的 变化。

那么,为什么我不应该编写一个单元测试,通过访问我的测试文件夹中的文件系统中的一些虚拟文件来验证解析例如 xls 文件的逻辑(例如 MS 测试允许使用 DeploymentItem)?

当然——如前所述——我们应该将这些测试与其他测试分开(可能在 JUnit 中的单独测试套件中)。但我认为,如果他觉得在那儿有这些测试很舒服的话,他也应该编写这些测试......显然,然后总是再次记住单元测试应该只测试一个单独的部分。

在我看来,最重要的是这些测试运行速度很快,而且不需要太长时间。它们可以重复且非常频繁地运行。

【讨论】:

  • Nit-pick:在您的 xls 解析示例中,通过重定向 IO 而不是从文件系统提供输入并在程序允许的情况下输出到 stdio 将是理想的。或者某种基于内存的文件系统。您可以认为这是真正孤立的,它允许并行运行测试。测试隔离并不是“真正的”单元测试的唯一标准,它还为更高级别的测试带来了重大好处。
  • 不只是速度的问题...您不需要进行任何配置工作,例如设置 RDBMS 来运行单元测试。比如,从 repo 中签出新的代码库 -> 运行测试 -> 全部为绿色。
【解决方案4】:

它没有断言,并且不期望抛出异常。

【讨论】:

  • +1:棘手的一个,我认为如果你错过了,你的 IDE 会给你一个错误或至少一个警告。 :-)
  • 我不认为有这样的警告,至少我使用的是(VS,NUnit)
  • 它悄无声息地过去了。在某些 IDE 中,您可以调整默认单元测试模板以包含 Assert.Fail() 或等效的测试方法的最后一行。这样,它将“默认失败”
  • 不是 100% 同意。您可以进行一些测试来测试某些代码是否运行而不会引发异常。这并不理想,但有时比什么都没有。你可以说总有一个隐含的断言表明被测单元不会抛出异常。
  • 你可以在没有断言的情况下进行单元测试。对于 MSTest 中的示例,您将编写一个单元测试来检查被测系统是否抛出了正确的异常。
【解决方案5】:

在以下情况下测试不是单元测试:

  • 它一次测试多个事物(即它测试两个事物如何协同工作) - 然后它是一个集成测试

良好的单元测试清单:

  • 它们是自动化的
  • 它们是可重复的
  • 它们很容易实现
  • 一旦写入,它们将留作将来使用
  • 任何人都可以运行它们
  • 只需按一下按钮即可运行它们
  • 他们跑得很快

更多最佳实践(按重要性不分先后):

  • 应将测试与集成测试(速度较慢)分开,以便尽可能快地运行它们
  • 它们不应包含太多逻辑(最好没有控制结构)
  • 每个测试都应该只测试一件事(因此,它们应该只包含一个断言)
  • 断言中使用的预期值应该是硬编码的,而不是在测试运行时计算
  • 应将外部依赖项(文件系统、时间、内存等)替换为存根
  • 测试应在测试关闭时重新创建初始状态
  • 在断言中,最好使用“包含...”策略,而不是“严格相等...”策略(即我们期望集合中的某些值、字符串中的某些字符等)

这是我从 Roy Osherove 的书中提取的部分知识 - The Art of Unit Testing

【讨论】:

  • 我认为“应该用存根替换外部依赖项(文件系统、时间、内存等)”不仅仅是最佳实践;-)
  • 使用模拟对象时,您可以通过检查是否调用了您的预期方法来遵循“包含”策略,但忽略调用其他方法。严格的模拟与此相反(它们在调用意外方法时抛出断言),并进行更脆弱的测试。当然,如果您要模拟的接口使得仅调用 x 次方法或以特定顺序调用某些方法很重要,那么您可能需要显式断言。该断言将被放置在它自己的单独测试中。
【解决方案6】:

跨多个可能失败的单元实施测试不是单元测试。

【讨论】:

    【解决方案7】:

    错综复杂的问题。

    假设我要编写一些业务逻辑,所有业务逻辑都需要通过某种形式的 DAL 获取数据。

    假设出于测试目的,我模拟了 DAL 单元(通过创建“知更鸟”)。

    当然,那些知更鸟本身就是额外的单位。因此,即使使用模拟,当我想对我的业务逻辑模块进行单元测试时,我似乎仍然会违反“不涉及其他单元”的想法。

    当然,众所周知,“为 DAL 创建模仿鸟”会使您的测试本身无效,因为您的模仿鸟在某些特定方面偏离了 DAL。

    结论:完全不可能对以任何方式依赖于任何类型 DAL 的业务模块进行“真正的单元测试”,问号?

    推论:唯一可能(“真正”!)单元测试的是 DAL 本身,问号?

    推论的推论:鉴于“DAL”通常是 ORM 或某些 DBMS 的 DML,并且鉴于这些产品通常作为“经过验证的技术”购买,那么做任何事情的附加价值是什么?单元测试,问号?

    【讨论】:

    • 有趣的想法 :-) .... 我不会这样说:“在业务模块上进行'真正的单元测试'是完全不可能的 .... 我不会说DAL 可以进行单元测试....
    • 您必须始终假设(即确保)您模拟接口以提供您期望的实现结果,以便模拟和真实对象之间存在关联。因此,我必须不同意您的推论:当然,可能很难完全模拟 DAL 的工作方式,特别是如果 DAL 是您自己没有编写的 ORM 工具。但是,通过正确地模拟它,您仍然可以测试业务模块,并且通过模拟业务模块的接口,您可以轻松地测试链中“稍后”的任何内容。
    • 我也在处理 DAL 层,最糟糕的是单元测试比编码需要更多时间。有些东西你可以测试,有些东西你根本无法测试,除非你假设数据。有一些测试会间歇性地通过(例如 IO 相关的东西很容易给出意想不到的结果)。另一个问题是我不能一起运行所有测试用例。 UTC 取决于州。
    【解决方案8】:

    确定一个测试是否是单元测试之后,下一个问题是,它是good unit test吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-21
      • 2018-01-18
      • 2011-12-31
      • 1970-01-01
      • 2010-11-07
      • 1970-01-01
      相关资源
      最近更新 更多