【问题标题】:Tricks for writing better unit tests [closed]编写更好的单元测试的技巧[关闭]
【发布时间】:2010-10-16 12:47:51
【问题描述】:

你们使用哪些技巧、工具或策略(除了具有单元测试标准)来编写更好的单元测试?更好的意思是“在尽可能少的测试中覆盖尽可能多的代码”。我说的是你使用过的东西,并且看到你的单元测试有了突飞猛进的进步。

例如,前几天我尝试了Pex,我认为它真的非常好。我错过了一些测试,Pex 轻松地告诉我在哪里。不幸的是,它有一个相当严格的许可证。

那么你们正在使用/正在做的其他一些很棒的东西是什么?

编辑:很多好的答案。我将标记为正确的答案,我目前没有练习,但肯定会尝试,希望能带来最好的收益。谢谢大家。

【问题讨论】:

  • 我没见过 Pex,看起来很可爱,我认为单元测试是编写代码的好地方。
  • “在尽可能少的测试中覆盖尽可能多的代码”真的更好吗?简洁是好的,但单一职责原则也是如此。

标签: unit-testing testing


【解决方案1】:
  1. 为每个方法编写许多测试。
  2. 尽可能测试最小的东西。然后测试下一个最小的东西。
  3. 测试所有合理的输入和输出范围。 IOW:如果您的方法返回布尔值,请确保测试 false 和 true 返回。对于整数? -1,0,1,n,n+1(通过数学归纳证明)。不要忘记检查所有异常(假设是 Java)。 4a。先写一个抽象接口。 4b。其次编写测试。 4c。最后写你的实现。
  4. 使用依赖注入。 (对于 Java:Guice - 据说更好,Spring - 可能已经足够好了)
  5. 使用像mockito 这样的好工具包来模拟你的“单位”合作者(再次假设Java)。
  6. 谷歌很多。
  7. 继续努力。 (我花了 2 年时间——除了谷歌之外没有太多帮助——开始“了解它”。)
  8. 阅读一本关于该主题的好书。
  9. 冲洗,重复...

【讨论】:

    【解决方案2】:

    在编写代码之前编写测试(即:测试驱动开发)。如果由于某种原因您以前无法编写测试,请在编写代码时编写它们。确保所有测试最初都失败。然后,顺着列表往下看,按顺序修复每个损坏的。这种方法将带来更好的代码和更好的测试。

    如果您有时间,您甚至可以考虑编写测试,将其忘掉一周,然后再编写实际代码。这样你就离问题更远了,现在可以更清楚地看到问题。如果任务来自外部或内部来源,我们的大脑会以不同的方式处理任务,而这种中断使其成为外部来源。

    在那之后,不要太担心它。单元测试为你提供了一个健全的检查和稳定的基础——仅此而已。

    【讨论】:

    • 忘记测试代码的提示很好=> +1
    【解决方案3】:

    在我当前的项目中,我们使用一个小型生成工具为各种实体和访问器生成框架单元测试,它为每个需要测试的模块化工作单元提供了相当一致的方法,并且为开发人员提供了一个测试其实现的好地方(即默认情况下添加其余实体和其他依赖项时添加单元测试类)。

    (模板化)测试的结构遵循相当可预测的语法,并且模板允许实现特定于模块/对象的构建/拆卸(我们还为所有测试使用基类来封装一些逻辑)。

    我们还在静态函数中创建实体实例(并分配测试数据值),以便可以通过编程方式创建对象并在不同的测试场景和跨测试类中使用,事实证明这非常有用。

    【讨论】:

    • 这个工具叫什么名字?免费/开源?
    • 这是我自己写的(花了大约一个小时,加上随着时间的推移对模板进行了调整)但它很容易完成 - 我很快就会写一篇关于这种方法的博客文章
    【解决方案4】:

    阅读像The Art of Unit Testing 这样的书肯定会有所帮助。

    【讨论】:

      【解决方案5】:

      就 SO 上的 Kent Beck's answer 政策而言,特别是:

      尽可能少地测试以达到给定的置信水平

      为代码的棘手部分编写实用的单元测试,不要忘记你正在测试的程序比单元测试重要这一事实。

      【讨论】:

        【解决方案6】:

        我有一个 ruby​​ 脚本,它为不是用 TDD 构建的“棕色”代码生成测试存根。它编写我的构建脚本,设置包含/使用并编写设置/拆卸以实例化存根中的测试类。当我破解在黑暗时代编写的代码时,有助于从一个一致的起点开始,而无需所有的打字乏味。

        【讨论】:

          【解决方案7】:

          我发现一个非常有用的做法是让您的测试套件同构到被测试的代码。这意味着测试的排列顺序与它们正在测试的代码行的顺序相同。这使得获取一段代码和该代码的测试套件变得非常容易,并排查看它们并逐步检查每一行代码以验证是否存在适当的测试。我还发现,仅仅像这样强制执行同构的行为就迫使我仔细考虑正在测试的代码,例如确保代码中所有可能的分支都经过测试,或者所有循环条件都经过测试。

          例如,给定如下代码:

          void MyClass::UpdateCacheInfo(
              CacheInfo *info)
          {
              if (mCacheInfo == info) {
                  return;
              }
              info->incrRefCount();
              mCacheInfo->decrRefCount();
              mCacheInfo = info
          }
          

          此功能的测试套件将按顺序进行以下测试:

          test UpdateCacheInfo_identical_info
          test UpdateCacheInfo_increment_new_info_ref_count
          test UpdateCacheInfo_decrement_old_info_ref_count
          test UpdateCacheInfo_update_mCacheInfo
          

          【讨论】:

            猜你喜欢
            • 2011-05-25
            • 2015-08-29
            • 2021-06-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-01-09
            相关资源
            最近更新 更多