关于测试驱动开发的Philisophical问题

Bil*_*ill 18 testing tdd unit-testing

我一直对测试驱动的开发感兴趣,但是当我在实际项目上尝试它时,我永远无法完成它.我尝试时会不断出现一些哲学问题:

  1. 你如何处理大的变化?在测试单个函数(一些参数,结果值,几个副作用)时,TDD是一个明智的选择.但是当你需要彻底检修大型的东西时,例如从SAX解析库切换到DOM解析库呢?当代码处于中间状态时,如何保持测试代码重构周期?一旦你开始进行更改,你将获得一系列失败的测试,直到你完成大修(除非你保持某种类型的mongrel类同时使用DOM和SAX,直到你完成转换,但这很奇怪) .在这种情况下,小步测试代码重构循环会发生什么?在整个过程中,您将不再进行小型,经过全面测试的步骤.人们必须以某种方式处理这个问题.
  2. 使用模拟测试GUI或数据库代码时,您真正在测试什么?模拟是为了准确地返回您想要的答案而构建的,那么您如何知道您的代码将与真实数据库一起使用?自动化测试对这类事情有什么好处?它在某种程度上提高了信心,但是a)它没有给你完全单元测试应该具有的相同水平的信心,并且b)在某种程度上,你不是简单地验证你的假设是否适用于你的代码而不是您的代码是使用DB还是GUI?

有人能指出我在大型项目中使用测试驱动开发的良好案例研究吗?令人沮丧的是,我基本上只能找到单个类的TDD示例.

谢谢!

Tho*_*ung 4

你如何应对巨大的变化?

根据需要尽可能小。

有时重构表面很大,但细节却微不足道。这些可以通过相当大的步骤来完成。花太多的精力去试图分解它们将是浪费。

我认为 XML 库的更改就属于这一类。您将 XML 放入并获取一些表示形式。只要您的表示没有改变(从表示状态的图形到事件流),库切换就很容易。

大多数时候重构并不是微不足道的,必须进行分解。问题是何时采取更大的步骤,何时采取更小的步骤。我的观察是,我不太擅长估计变革的影响。大多数软件都非常复杂,您可能认为它们的更改很容易管理,但随后整个细则必须再次工作。所以我确实从一些改变开始。但如果事情开始变得不可预测,我准备回滚一切。我想说这种情况发生在十分之一的重构中。但这会很难。您必须找出系统中未按预期运行的部分。现在必须将问题分解为多个较小的问题。我确实一次解决一个问题,并在完成后检查。(多次迭代的恢复和分裂并不罕见。)

如果您更改代码中的 XML 解析器和表示形式,这肯定至少需要两次单独的重构。

模拟测试

您正在使用模拟对象测试对象/层之间的通信协议。

整个模拟方法可以被视为像OSI 模型一样的通信模型。当 X 层得到参数 x 的调用时,它将调用带有参数 a 和 b 的 Z 层。您的测试指定了此通信协议。

尽管模拟测试很有用,但使用它们测试尽可能少的功能。最好的选择是基于状态的测试:设置固定装置、调用被测系统、检查被测系统的状态和纯功能(如函数式编程)测试:用 x 调用返回 a。

尝试以大多数功能松散耦合的方式设计系统。有些功能必须通过模拟测试来测试(完全解耦的系统是没有用的)。

集成测试不是测试您的系统的选项。它们只能用于测试系统中可能因多个单元的集成而中断的方面。如果您尝试通过集成测试来测试您的系统,您将进入排列赌场。

所以你的 GUI 测试策略应该是明确的。GUI 代码中无法单独测试的部分应使用模拟测试进行测试(按下此按钮时,将使用参数 y 调用服务 X)。

数据库有点把水搅浑了。您不能模拟数据库,除非您要重新实现您想要支持的每个数据库的行为。但这不是单元测试,因为您正在集成外部系统。我已经接受了这个概念问题,并将 DAO 和数据库视为一个不可分割的单元,可以使用基于状态的测试方法进行测试。(遗憾的是,这个单元在 Oracle 日和 mysql 日时的行为有所不同。并且它可能会在中间中断并告诉您它无法与自己对话。)