【发布时间】:2009-01-24 16:23:29
【问题描述】:
在哪些情况下单元测试和 TDD 之类的东西比它们的价值更麻烦?
我想出的一些事情是:
- 当生成测试数据很棘手时:有时,能够提出有效的、非平凡的测试数据本身就是一个挑战。
- 验证代码正确性的唯一实用方法是运行它。
- 当您测试设计的视觉元素时。
还有哪些其他情况?
【问题讨论】:
在哪些情况下单元测试和 TDD 之类的东西比它们的价值更麻烦?
我想出的一些事情是:
还有哪些其他情况?
【问题讨论】:
我相信你的前两点是无效的。
应用程序的方面肯定是无法进行单元测试的 - 视觉布局(屏幕或打印)就是这样一个方面,一般来说可用性也是如此 - 无法真正正式指定的东西。
单元测试可能不适用的情况是,当您面临的现有应用程序在开发时没有考虑可测试性甚至模块化(Big Ball of Mud 反模式)。但即便如此,如果您知道您必须在相当长的时间内维护和扩展这个野兽,那么找到一种方法来自动测试应用程序的至少某些部分几乎总是可行且有用的。没有人说你必须先编写一个测试套件来实现 100% 的代码覆盖率,然后再做任何其他事情。
【讨论】:
我不确定它是否没有帮助。在某些情况下,它可能会更困难,您可能会选择不使用它——例如,在您的 UI 的视觉布局的情况下。有时也可能会浪费精力——例如,对设计人员生成的代码或不是您编写的框架进行单元测试。生成数据不应该成为单元测试的障碍。您的测试应该足够小并且足够集中,以至于您通常不需要为任何单个测试生成整个数据集,因此在这些情况下模拟是一种非常有用的技术。如果我发现自己一遍又一遍地嘲笑同样的事情,我有时会将它合并成一个所有测试都可以依赖的假数据库类。
单元测试和运行代码都不会验证其正确性。单元测试可以帮助消除错误,尤其是 TDD,并确保发现的错误得到修复。如果您需要确保您的代码是正确的,您将需要应用不同的、基于逻辑的技术来证明正确性。这些超出了单元测试的范围。
【讨论】:
我认为迈克尔总结得非常好:“不能真正正式指定的事物”。原来有很多东西不能正式指定。可用性就是一个例子(尽管一旦你决定了哪种行为是可用的,你当然可以而且应该测试那个行为!)。有点自相矛盾的是,许多数字运算任务无法正式指定:例如天气预报。目标当然是预测明天的天气,但这不是一个正式的规范。所以你可以测试你使用的算法是否做了它们应该做的事情(计算平均值、反转矩阵、可以正式指定的东西),但是你的天气预报程序可以通过所有测试,但 90% 的时间仍然是错误的.或者,您可以使用大量历史数据来测试算法是否产生良好的预测,但这很危险,因为它很容易导致算法只对您使用的历史数据准确,而不是一般情况下。这可能意味着您的单元测试需要数小时或数天才能运行。更糟糕的是,您的算法可能具有必须“调整”的参数,例如对于所使用的测量仪器,每个算法的最佳参数可能并不相同,因此单元测试需要手动交互才能找到好的参数。理论上可行,但可能不是很有用。我想同样的论点也适用于 OCR、ICR、许多信号处理任务、人脸识别(以及许多其他图像处理任务)、典型的 Photoshop 工具(如“红眼消除”)或搜索引擎排名算法(仅举几个例子) )。
【讨论】:
我不会说自动化测试在任何情况下都没有帮助。
当然也有一些不太有用的地方。我不认为创建夹具数据是其中之一。有一些工具可以提供帮助,例如 factory_girl(至少在 Ruby 中)。实际上,如果您的模型非常复杂,以至于您需要创建十几个具有各种关联的对象,我会认为代码有异味,并且可能模型没有尽可能简洁。
也就是说,在某些情况下,弊端可能会超过好处。前几天我写了一些代码来分叉一个外部进程。我不关心输出,我不关心返回码,我什至不关心它是否工作正常,它完全是一劳永逸的,如果有什么事情不正常,另一个进程将被清理,稍后。
在那种情况下,我没有费心编写任何测试,因为这样做的好处不值得花时间设置一个虚假的外部程序来验证我的论点等等。
【讨论】:
只是对此的一些随机想法:
但这些仍然是极端情况。我还认为它们几乎总是可行的,而且从长远来看,它们通常会给你带来比你一开始的投资更多的回报。
【讨论】:
* When generating test data is tricky: Sometimes, being able to come up with valid, non trivial test data is a challenge in itself.
当您需要系统与“完整数据集”“在上下文中”时,您所做的不是单元测试。它正在测试,但是您对“单元”的压力很大。您需要为此进行 较小的 测试。 TDD 的难点在于让您的代码具有您可以在小范围内对其进行测试的形式。它很有价值,但并不容易。如果您进行后测试(不是 TDD),那么几乎不可能避免这种情况。
因此,当您想测试比单元更大的东西(即类上的方法)时,您将需要使用 UAT 之类的东西。但在这种情况下,您仍然需要像练习 TDD 一样对单个函数进行测试。
* When the only practical way of verifying correctness of the code is to run it.
但是代码是在单元测试中运行的。你的意思是当它在上下文中运行 或其他什么时候?
* When you're testing visual elements of the design.
我认为这是您的第二个要点,但我想不是。尝试在 UT 中测试布局是困难的,而且通常没有回报。这样的测试是脆弱的。
因此在某些情况下使用 UT 进行大型子系统测试或验证屏幕布局可能没有价值。但即便如此,它对于你剩下的 90% 的工作来说还是非常有价值的。
【讨论】:
我坚信深思熟虑的测试;但是,我发现单元测试和 TDD 主要是在浪费时间。
如果您的开发人员不是高素质的,那么单元测试可能会有一些好处。
【讨论】: