编写更好的单元测试的技巧

时间:2009-03-31 02:13:49

标签: unit-testing testing

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

作为一个例子,我前几天尝试Pex,我认为这真的很棒。我错过了一些测试,Pex很容易地向我展示了哪里。不幸的是,它有相当严格的许可证。

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

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

7 个答案:

答案 0 :(得分:11)

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

答案 1 :(得分:4)

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

如果你有时间陪伴,那么你甚至可以考虑编写测试,忘记一周,然后编写实际代码。通过这种方式,您可以远离问题,现在可以更清楚地看到问题。如果它们来自外部或内部来源,我们的大脑处理任务会有所不同,而这种突破使其成为外部来源。

之后,不要太担心。单元测试为您提供完整的检查和稳定的基础 - 这就是全部。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:1)

就政策在SO上阅读Kent Beck's answer,特别是:

  

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

为代码中棘手的部分编写实用的单元测试,并且不要丢失这样一个事实,即你正在测试的程序是重要的,而不是单元测试。

答案 5 :(得分:1)

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

答案 6 :(得分:1)

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

例如,给定代码如下:

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