【问题标题】:Unit Testing - What not to test单元测试 - 什么不测试
【发布时间】:2010-11-21 22:58:53
【问题描述】:

我浏览过很多关于 stackoverflow 的帖子和很多关于单元测试的文章。我只是想弄清楚我所理解的是否正确。

  1. 不要测试任何不涉及逻辑的东西。例如:如果服务层有一个方法简单地调用了数据访问层的另一个方法,不要测试它。

  2. 不要测试基本的数据库操作。如果我在 DAL 中有一个方法可以简单地在数据库中插入一个对象,比如“public void save(Object object){...}”并且没有对从服务层接收到的对象进行任何处理,不要测试一下。

  3. 我不需要验证所有层的对象。这意味着对象中的某个字段不应为空,例如用户对象中的 emailId,并且这在 JSP(使用 JS)中得到验证和验证,我不需要测试 DAL 方法在收到 emailId 时的行为=NULL,因为理想情况下它不应该,这应该由 JS 处理。

还有什么我不应该测试的?

【问题讨论】:

  • 这是一个非常复杂且取决于项目的问题。结论应该是检查你的方法,并决定哪些是微不足道的要测试,哪些是足够复杂的,可以测试。

标签: unit-testing


【解决方案1】:

我不确定我是否同意任何您在回答中提到的例外情况。

不涉及逻辑的方法

即使一个方法只是简单地将其实现委托给一个内部依赖项,验证它是否发生也非常重要。我认为您编写代码是有原因的,因此您需要编写一个测试来确保它保持这种状态。

请记住,单元测试的主要好处之一是作为回归测试套件。正确调用内部依赖项的测试称为交互测试。假设你有以下方法:

public void Save(Entity entity)
{
    this.repository.Save(entity);
}

测试是否使用正确的输入调用了存储库的 Save 方法非常重要。否则,其他开发人员可能会在以后出现并删除该行代码,而回归测试套件不会提醒您。

记住:简单的事情并不一定会保持简单。

不测试数据库操作

您是否认为数据是否正确地保存在数据库中无关紧要?如果你真的,真的,不在乎,那么你就不需要测试它 - 否则你需要。

如果你不测试你的数据库操作,你怎么知道你的数据访问组件有效?

我并不是说您应该测试您的 ORM 库,但您应该测试它是否被正确使用。

不在所有层中测试对象

我不确定你的这个问题是什么意思,但是如果一个字段可以为空,这是一个问题,你需要测试当它实际上是空时会发生什么 - 无处不在。

那么,设计您的 API 以保证值不为空是更可取的。

结论

您应该测试您可以测试的所有内容。没有例外。简单的事情不会保持简单,您需要能够验证曾经有效的代码是否继续有效。

有些东西(例如 UI)是您不能进行单元测试的,这些东西应该被抽象出来,以便它们包含尽可能少的逻辑,但其他所有东西都应该进行测试。

测试驱动开发 (TDD) 是确保实现这一目标的最佳方式。

【讨论】:

  • 我认为您误解或错误引用了 OP:他不是说“不要测试这些东西”,而是说“不要unit-test it” .很多人(像你一样)似乎在谈论单元测试时好像单元测试是唯一的测试类型(和/或唯一的自动化测试),因此单元测试是过度的评级。
  • 据我了解,单元测试不应该与数据库交互,并且每个方法都应该单独测试,如果是这样,我应该在单元测试中为您显示的代码的 sn-p 编写什么?
  • 存储库应该是注入的依赖项。然后,您可以使用 Mock 来验证其 Save 方法是否被正确调用。
  • “请参阅 stackoverflow.com/questions/1316101/... 进行详细说明” - 没有真正详细说明:它只是断言(没有任何解释或证据)单元测试是“最有效和强大的自动化测试类型”。 IMO 它们既不高效也不健壮:因为单元测试是依赖于实现的(unit-dependent),因此如果重构实现,它们会很脆弱(即需要更改)。
  • @ChrisW:单元测试通常更健壮,因为当您更改不再有效的内容时会出现编译错误。我更喜欢必须维护复杂的部署脚本,这些脚本总是失败并且反馈周期更长。绝对有可能编写不脆弱的单元测试。您在谈论的是一种称为 Fragile Test 的反模式。我想推荐一本书“xUnit 测试模式”,它解释了如何避免它。
【解决方案2】:

不要测试任何不会失败的东西。

但更符合你的观点。

  1. 这一切都取决于您所说的逻辑。我在映射层上采用了这种方法。我没有测试将属性值从对象 A 复制到对象 B 的所有无聊代码。错误的复制粘贴,我复制了一个副本并错过了另一个。大事件。但是值得所有额外的测试代码吗?取决于应用程序失败时会发生什么。在这种情况下,测试代码是值得的。

  2. 类似于第一点。所以 Save 既好又简单,但你怎么知道你做对了简单的事情。搞砸这些和弄错一点业务逻辑一样糟糕。

  3. 您不想重新测试您已经测试过的东西。但是你应该超越单元测试。进行集成和回归测试以及单元测试。当所有部件都在真空中工作但放在一起时会爆炸,这真的很棒。

测试是一种平衡行为。如果你真正测试它,你可能永远不会完成任何其他事情。但是如果你没有对它进行足够的测试,你就会把所有的时间都花在修复错误上。平衡点在哪里发生变化。不同类型的项目有不同的失败成本。在某些项目中,例如了解内部用户的项目,您可能能够轻松而快速地运行,但能持续多久?最终,未经测试的代码会中断,需要一段时间才能找到并且您没有取得任何进展。

最好的做法是遵循真正的 TDD。不要为了测试而测试。测试作为设计技术。测试,因为它会排除松散耦合的代码。测试是因为在两个上下文(测试和应用程序)中执行代码会产生更好的代码。一旦你走上了 TDD 的道路,你就不会问你应该和不应该测试什么。测试只是编写代码的一部分,而不是独立的活动。

【讨论】:

  • 1.一切都可能失败 - “这不能失败”是著名的遗言...... 2. 无聊的 C&P 代码是要测试的主要成员,因为它连接到层,就像你说的那样。此处失败会使整个软件失败,因为传递了错误/丢失的数据。由于这似乎也在主要用例中,因此确实需要对其进行测试。
  • @BeowulfOF 1. 这就是重点。说不要测试不能失败的东西,这是一个公认的轻率反应。这是一个古老的规则,通常情况下,未说明的推论是一切都可能失败。通常,当您大声说出第一部分时,您所说的方式会使第二部分清楚。 2.关于复制粘贴代码的故事的重点是我犯了一个很大的错误,没有测试它。所以我同意你的看法。
  • @MikeTwo 关于你的第二点——我同意应该测试数据是否被保存——但不是“单元测试”,问题是关于单元测试的。
  • @Mashur。我知道它很挑剔,但我没有说测试是否保存数据。我说测试保存。这可能意味着很多事情,比如测试 Save 可能通过使用模拟来处理来自底层持久性的错误。保存自己很少只是保存数据。
【解决方案3】:

简单的答案 - 没有

复杂的答案 - 你不应该测试你没有时间做的事情。 测试由对所需和负担得起的测试的复杂规划驱动,优先考虑软件系统最重要的部分和工作流程。留给测试的时间越多,可以测试的sidecases就越多。

在 UnitTesting 中,每个单元,在 OOP 中,每个类都有自己的测试。使用最小值、最大值、平均用例值简单地测试所有内容并进行否定测试 - 如果软件工作正常,测试必须失败。也测试错误处理。

有关该主题的更多详细信息,请参阅ITSQB

【讨论】:

    【解决方案4】:

    一般来说,如果可能的话,我会选择 TDD 风格。这很难实现,需要大量的纪律,但如果你拥有它,你就再也不想回来了。顺便说一句,TDD 不仅仅是关于测试,更多的是关于软件设计(也可以称为测试驱动设计)。您的设计会根据您的测试而发展。

    Mark 确实对你关于不测试的陈述给出了一个很好的答案。

    我不需要验证对象 所有层。这意味着某个领域 在一个对象中不应该为空,比如说 用户对象中的 emailId 和这个 在 JSP(使用JS),我不需要测试 如果 DAL 方法的行为 收到 emailId=NULL,因为理想情况下 它不应该,这应该是 由 JS 照顾。

    在分层应用程序中,您的应用程序可能有两种“前端”/入口点。一个可能是普通的 Web 用户界面,另一个可能是由其他应用程序(可能是桌面应用程序)使用的 Web 服务。因此,所有与验证相关的逻辑都应该(也)在业务层中检查(因为验证可能是业务逻辑的一部分)。

    【讨论】:

      【解决方案5】:

      不要对 .NET 框架进行单元测试。我的意思是,不要测试微软负责的事情。

      例如,不要费心测试 setter 和 getter - 除非其中包含实际代码。

      【讨论】:

        【解决方案6】:

        等等,你说的 JS 是指 JavaScript 吗?我假设您指的是客户端验证? 您永远不应该假设客户在构建网站时会验证任何内容。可以禁用 JavaScript,可以更改或伪造页面等。

        【讨论】:

        • JS 指的是 JavaScript,但它更像是试图识别每一层的责任,它可能是控制器而不是 JS,我只想弄清楚你是否需要测试是否一个值在所有层(控制器、服务和 Dada 访问)都是空的,会有很多重复的代码,或者换句话说,如果接收层在理想情况下没有收到无效对象,并且按照约定不应收到无效对象
        【解决方案7】:

        我不同意你的观点。您不应该根据现在的代码编写方式来编写单元测试,而是要确保将来,如果另一个开发人员更改了代码的某些随机部分,他可以运行它们并确信一切都很好。

        例如,您可能想要测试仅调用另一个方法的方法。毕竟,您只对外部方法的工作方式感兴趣,而不是它如何工作。如果下一位开发人员更改了外部方法,使其不再那么简单,他将错过单元测试。

        这就是为什么你应该使用像NCover这样的工具来确保你的代码100%在单元测试中执行的原因!

        【讨论】:

          【解决方案8】:

          如果您有已经可以使用的东西,则可能不值得花时间围绕它编写一堆测试。这里需要注意的是,如果您需要对其或使用它的代码进行更改,那么这些测试是无价的。

          至于不需要测试 DAL 对无效输入的处理......你需要弄清楚你的服务边界是什么。这真的取决于。如果您无法控制客户端,那么您需要测试您的服务器的期望是否得到满足(在某个层面)。

          【讨论】:

            【解决方案9】:

            我不是 unit 测试任何东西,因为我希望 integration 和/或 system 测试:

            • 覆盖代码
            • 自动化
            • 用作单元测试,并与单元测试一样有用

            详情见Should one test internal implementation, or only test public behaviour?

            扭转你的问题,我建议你应该单元测试的唯一代码是代码:

            a) 哪个根本不会通过集成和/或系统测试进行测试(如果没有,为什么不呢?)

            b) 或者,无论出于何种原因,应该在集成/系统测试之前进行测试(可能是因为您的项目开发是如何被并行分配给多个开发人员的)

            【讨论】:

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