【问题标题】:How do i really unit test code?我如何真正对代码进行单元测试?
【发布时间】:2019-08-02 21:14:14
【问题描述】:

我正在阅读Joel Test 2010,它让我想起了单元测试的一个问题。

我如何真正进行单元测试?我不单元测试功能?只有全班?如果我有 15 个小于 20 行的类怎么办。我是否应该为每个类编写一个 35 行单元测试,将 15*20 行变为 15*(20+35) 行(从 300 到 825,代码增加近 3 倍)。

如果一个类只被模块中的两个其他类使用,我应该对它进行单元测试还是对其他两个类进行测试就足够了?如果它们都是

如果我编写代码来转储数据并且我不需要读取它,例如使用另一个应用程序。另一个应用程序不是命令行,或者它是但无法验证数据是否良好。我还需要对它进行单元测试吗?

如果应用程序是一个实用程序并且总代码少于 500 行,该怎么办。或者是那周使用的,将来会使用,但总是需要重新配置,因为它是为了快速批处理,每个项目都需要调整,因为期望的输出没有改变。 (我想说没有办法解决它,出于正当理由,它总是会被调整)我是否对它进行单元测试,如果是的话如何? (也许我们不关心我们是否破坏了过去使用但现在或将来不使用的功能)。

等等

我认为这应该是一个维基。也许人们想确切地说他们应该单元测试(或不应该)什么?也许书籍的链接很好。我尝试了一个,但它从未阐明应该进行单元测试的内容,只是编写单元测试和解决方案的问题。


此外,如果类仅用于该项目(根据设计、规范或任何其他原因),并且该类本身没有用(假设它使用返回 html 就绪 cmets 的数据生成 html)我真的需要测试它?当我的项目不使用空注释时,检查所有公共函数是否允许空注释对象。正是这些事情让我想知道我是否在单元测试错误的代码。项目时也有大量的类是一次性的。它的边界一次性或不是很有用的单独代码困扰我。

【问题讨论】:

标签: unit-testing


【解决方案1】:

以下是我所听到的,无论您是不是这个意思:一连串的问题和借口,为什么单元测试可能不适用于您的代码。换句话说:“我看不出我会从单元测试中得到什么,而且它们写起来很麻烦;也许它们不适合我?”

你知道吗?你可能是对的。单元测试不是灵丹妙药。单元测试无法涵盖大量广泛的测试。

不过,我认为您错误地估计了维护成本,以及您的代码中可能出现的问题。所以这是我的想法:

  • 我应该测试小班吗? 是的,如果那个班有可能会破坏的东西。
  • 我应该测试函数吗? 是的,如果这个函数中有可能会破坏的东西。你为什么不呢?或者您是否担心它是否被视为一个单位?这只是对名称的争论,与您是否应该为它编写单元测试没有任何关系!但根据我的经验,将方法或函数描述为被测单元是很常见的。
  • 如果一个类被其他两个类使用,我应该对它进行单元测试吗? 是的,如果该类中有任何可能破坏的东西。 我应该单独测试它吗? 这样做的好处是能够将损坏直接隔离到共享类,而不是通过使用类来查看是它们损坏了还是其中之一它们的依赖关系。
  • 如果另一个程序可以读取我的班级的数据输出,我应该测试它吗? 是的,尤其是如果那个其他程序是第 3 方的!这是单元测试(或者可能是系统测试,取决于测试中涉及的隔离)的一个很好的应用:向自己证明您输出的数据正是您认为应该输出的数据。我想你会发现它有能力极大地简化支持电话。 (但请注意,它不能替代客户端的良好验收测试。)
  • 我应该测试一次性代码吗? 可能。追求 TDD 策略会让你的一次性代码更快地推出吗?它可能。拥有可以适应新约束的可靠的单元测试块会减少丢弃代码的需要吗?也许吧。
  • 我应该测试不断变化的代码吗? 是的。只需确保所有适用的测试都已更新并通过!毕竟,不断更改代码可能特别容易出错,并且启用安全更改是单元测试的另一个巨大好处。另外,它可能会给你的不变代码带来尽可能健壮的负担,以实现这种变化速度。而且您知道如何说服自己一段代码是否健壮...
  • 我应该测试不再需要的功能吗? 不,您可以删除测试,也可能删除代码(当然,测试以确保您没有破坏过程中的任何内容!)。不要让单元测试失效,特别是如果测试不再工作或运行,或者您组织中的人员将远离单元测试,您将失去好处。我见过这种情况。这不漂亮。
  • 我是否应该测试没有被我的项目使用的代码,即使它是在我的项目的上下文中编写的? 取决于你的项目的可交付成果是什么,以及你的项目的优先级是什么是。但是您确定项目之外的任何人都不会使用它吗?如果他们不会,而你不是,也许它只是死代码,在这种情况下见上文。从我的角度来看,如果我的测试没有涵盖它的所有重要功能,无论项目是否使用了所有这些功能,我都不会觉得我已经完成了一个类的完整工作。我喜欢感觉完整的课程,但我会注意不要过度设计一堆我不需要的东西。如果我将某些东西放在一个类中,那么我打算使用它,因此会想要确保它有效。这是我个人素质和满意度的问题。

【讨论】:

  • FWIW,不断变化的代码最有可能被破坏。滑倒做一些愚蠢的事情太容易了。 :-)
  • @Donal:我不知道最有可能,但你是对的。我为那个人拿出了“如果它可能打破”的口头禅。我们假设它可以。 :-)
  • “如果另一个程序会读取它,我应该测试我的类的数据输出吗?地狱是的”
  • 重新测试数据输出:应该不需要编写重型反序列化器,只需创建一个“黄金输出”文件并确保您的输出匹配它,使用 diff 或您选择的工具。
  • @acidzombie24,如果您不需要处理 UTF8,那么您为什么要实现对它的支持?额外的复杂性使调试您使用的功能变得更加困难。空值处理更多的是一个偏好问题——您可以检查所有参数是否为空并抛出异常,或者添加仅在调试版本中触发的断言,或者只是让它失败并出现空引用或访问冲突错误运行时,取决于你的商店风格(以及你对它不会在生产中发生的把握程度)。
【解决方案2】:

不要专注于计算代码行数。编写尽可能多的测试代码,让自己相信每一个关键功能都经过了彻底的测试。作为一个极端的例子,SQLite 项目的测试:源代码比率超过了600:1。我在这里很好地使用了“极端”这个词。正在进行的大量测试可能是 SQLite 占领世界的主要原因。

【讨论】:

  • “可能” ... 也可能不是 :-)
  • @acidzombie24:不,他们不是。
  • 我在看它,我不清楚,测试用例是在测试 sql 和数据库吗?还是在他们拥有的每个类和功能上?我不知道是前者还是后者。
  • AFAICT,所有测试都是系统测试(sql 和数据库),但开发人员在确保完整的分支覆盖方面非常彻底,第 7 节专门解释它。他们真的在这个地方进城了。
【解决方案3】:

您如何进行所有这些计算?理想情况下,您永远不应处于可以计算已完成课程的行数然后从头开始编写单元测试的情况。这两种类型的代码(真实代码和测试代码)应该一起开发和发展,最终真正让您担心的唯一 LOC 指标是测试代码的 0 LOC。

【讨论】:

    【解决方案4】:

    代码和测试的相对 LOC 计数毫无意义。更重要的是测试覆盖率。最重要的是找到错误。

    在编写单元测试时,我倾向于将精力集中在测试更可能包含错误的复杂代码上。简单的东西(例如简单的 getter 和 setter 方法)不太可能包含错误,并且可以通过更高级别的单元测试进行间接测试。

    【讨论】:

    • 现在我只测试我认为会给我带来问题的代码。例如转义给定的特定字符列表进行转义。以及当我期望使用各种东西时将数据转换为 sql 查询的代码。那和 bc 共享。这两个类我已经在几个项目中使用过。
    【解决方案5】:

    不久前,我与您在脑海中发布的相同问题。我研究了很多文章、教程、书籍等等......虽然这些资源给了我一个很好的起点,但我仍然对如何有效地应用单元测试代码感到不安全。在遇到xUnit Test Patterns: Refactoring Test Code 并将它放在我的书架上大约一年后(你知道,我们有很多东西要学习),它为我提供了有效应用单元测试代码所需的东西。通过许多有用的模式(和建议),您将了解如何成为一名单元测试编码员。主题为

    • 测试策略模式
    • 基本模式
    • 夹具设置模式
    • 结果验证模式
    • 测试双重模式
    • 测试组织模式
    • 数据库模式
    • 值模式

    等等……

    例如,我将向您展示派生值模式

    当我们需要测试一个将复杂对象作为参数的方法时,通常会使用派生输入。例如,彻底的输入验证测试要求我们将对象的每个属性设置为一个或多个可能的无效值。因为第一个被拒绝的值可能会导致方法的终止我们必须在单独的调用中验证每个坏属性。我们可以轻松实例化无效对象首先创建一个有效对象,然后用无效值替换它的一个属性

    与您的问题相关的测试组织模式(测试用例类每个功能

    随着测试方法数量的增长,我们需要决定使用哪个测试用例类来放置每个测试方法...使用一个测试用例类每个特性给了我们一个系统的方法打破将一个大的 Testcase 类分成几个较小的类,而无需更改测试方法。

    但在阅读之前


    (来源:xunitpatterns.com

    我的建议:仔细阅读

    【讨论】:

      【解决方案6】:

      您似乎担心测试代码可能比被测代码多。

      我认为我们的比率可能比你说的要高。我希望任何严肃的测试都能进行广泛的投入。所以你的 20 行类很可能有 200 行测试代码。

      我不认为这是一个问题。对我来说有趣的是,编写测试似乎并没有让我慢下来。相反,它让我在编写代码时专注于代码。

      所以,是的,测试一切。尽量不要将测试视为一件苦差事。

      【讨论】:

      • 我认为的一个问题是在验证我需要调试的错误时可能存在更多错误,而不是我正在测试的代码很小、很好(在看到它运行正常之后)并且永远不需要再次被触摸。
      • 还有很多是项目特定的代码。我在其他项目中不需要它们。所以我可以只使用项目中可用的特定范围。你也没有提到你是否测试了一个其他两个类使用的类,并且只有这两个类。你是测试共享类还是彻底测试两者?我发现这个类是一个助手,它唯一的规范是做其他两个类需要的任何东西。这听起来像一个函数,但复杂到足以成为一个对象。
      【解决方案7】:

      我所在的团队刚刚开始将测试代码添加到我们现有的、相当陈旧的代码库中。
      我在这里使用“测试”是因为我觉得它可能非常模糊,无法判断它是单元测试、系统测试、集成测试等。术语之间的差异有很大的灰色区域,并没有增加很多价值。

      因为我们生活在现实世界中,我们没有时间为所有现有功能添加测试代码。我们仍然有发现大多数错误的测试人员 Dave。相反,随着我们的开发,我们编写测试。在告诉老板它有效之前,您知道如何运行代码吗?好吧,使用单元框架(我们使用 Junit)来执行这些运行。并且只保留它们,而不是删除它们。无论您通常做什么来说服自己它有效。这样做。

      如果编写代码很容易,那就去做吧。如果没有,请把它留给 Dave,直到你想出一个让它自动化的好方法,或者直到你在“他们”试图决定在下一个版本中添加什么的项目之间有空闲时间。

      【讨论】:

        【解决方案8】:

        对于java你可以使用junit

        JUnit

        JUnit 是一个用于编写可重复测试的简单框架。它是用于单元测试框架的 xUnit 架构的一个实例。

        * Getting Started
        * Documentation
        * JUnit related sites/projects
        * Mailing Lists
        * Get Involved
        

        开始 要开始使用单元测试和 JUnit,请阅读文章:JUnit Cookbook。 本文介绍了使用 JUnit 4 编写的基本测试。

        您可以在 org.junit.samples 包中找到其他示例:

        * SimpleTest.java - some simple test cases
        * VectorTest.java - test cases for java.util.Vector
        

        JUnit 4.x 仅附带一个文本 TestRunner。对于图形反馈,大多数主要 IDE 都支持 JUnit 4。如果需要,您可以在每个测试类中添加以下方法,在 JUnit 3 环境中运行 JUnit 4 测试:

        公共静态测试套件(){ 返回新的 JUnit4TestAdapter(ThisClass.class); }

        文档

        JUnit Cookbook
            A cookbook for implementing tests with JUnit.
        Javadoc
            API documentation generated with javadoc.
        Frequently asked questions
            Some frequently asked questions about using JUnit.
        Release notes
            Latest JUnit release notes
        License
            The terms of the common public license used for JUnit.
        

        以下文档仍描述 JUnit 3.8。

        The JUnit 3.8 version of this homepage
        Test Infected - Programmers Love Writing Tests
            An article demonstrating the development process with JUnit.
        JUnit - A cooks tour 
        

        JUnit 相关项目/站点

        * junit.org - a site for software developers using JUnit. It provides instructions for how to integrate JUnit with development tools like JBuilder and VisualAge/Java. As well as articles about and extensions to JUnit.
        * XProgramming.com - various implementations of the xUnit testing framework architecture. 
        

        邮件列表 共有三个junit邮件列表:

        * JUnit announce: junit-announce@lists.sourceforge.net Archives/Subscribe/Unsubscribe
        * JUnit users list: junit@yahoogroups.com Archives/Subscribe/Unsubscribe
        * JUnit developer list: junit-devel@lists.sourceforge.net Archives/Subscribe/Unsubscribe
        

        参与进来 JUnit 庆祝程序员测试他们自己的软件。因此,与没有的相比,包含 JUnit 测试用例的错误、补丁和功能请求更有可能得到解决。 JUnit 源代码现在托管在 GitHub 上。

        【讨论】:

          【解决方案9】:

          一种可能性是将“测试代码”简化为描述测试的语言,以及运行测试的解释器。我参与过的团队已将其用于出色的目的,使我们能够编写比“代码行数”所表明的更多的测试。

          这使我们的测试编写得更快并且大大提高了测试的易读性。

          【讨论】:

          • 这是一种内部语言还是您使用了什么?
          • @acidzombie24,这是一种内部语言:我们的产品非常小众,并且没有现有的语言来描述我们的问题领域。幸运的是,我们可以编写一个简单的语言解释器;测试框架需要编写更多的工作。 (也许 shell 是框架的错误语言,但我们不希望在运行框架时有太多依赖。)
          【解决方案10】:

          我将回答我认为是您问题的要点。首先,你应该写多少测试代码?好吧,Test-Driven Development 可以在这里提供一些帮助。我没有像理论上建议的那样严格使用它,但我发现先编写测试通常可以帮助我更好地理解我想要解决的问题。此外,它通常会导致良好的测试覆盖率。

          其次,您应该测试哪些类?同样,TDD(或更准确地说是它背后的一些原则)可以提供帮助。如果您开发您的系统top down 并首先编写您的测试,那么您将在编写内部类时对外部类进行测试。如果内部类有错误,这些测试应该会失败。

          TDD 也与Design for Testability 的想法紧密结合。

          我的回答不是为了解决你所有的问题,而是给你一些想法。

          【讨论】:

            【解决方案11】:

            我认为不可能就应该和不应该进行单元测试的内容编写一份全面的指南。对象、类和函数的排列和类型太多,无法涵盖所有​​内容。

            我建议将个人责任应用于测试,并自己确定答案。这是你的代码,你负责它的工作。如果它坏了,你必须为修复代码、修复数据、对收入损失负责,并向那些试图使用它的应用程序坏了的人道歉。底线 - 你的代码永远不应该中断。那么,您需要做些什么来确保这一点?

            有时单元测试可以很好地帮助您测试库中的所有特定方法。有时单元测试只是忙碌的工作,因为您可以根据您在更高级别测试期间对代码的使用来判断代码正在运行。您是开发人员,您有责任确保代码永不中断 - 您认为实现这一目标的最佳方法是什么?

            如果您认为单元测试在特定情况下是浪费时间 - 可能是这样。如果您已经在所有应用程序用例场景中测试了代码并且它们都可以工作,那么代码可能很好。

            如果代码中发生了您不理解的事情——即使最终结果是可以接受的——那么您需要做更多的测试以确保没有什么是您不理解的。

            对我来说,这似乎是常识。

            【讨论】:

              【解决方案12】:

              单元测试主要是从功能方面测试您的单元。您可以测试并查看是否有特定输入,我们会收到预期值还是会抛出正确的异常?

              单元测试非常有用。我建议你写下这些测试。但是,并非所有内容都需要进行测试。例如,您不需要测试简单的 getter 和 setter。

              如果您想通过 Eclipse 用 Ja​​va 编写单元测试,请查看“How To Write Java Unit Tests”。我希望它有所帮助。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2014-01-28
                • 1970-01-01
                • 1970-01-01
                • 2010-12-29
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-09-05
                相关资源
                最近更新 更多