《测试驱动的嵌入式C语言开发》——3.6节增量式前进

    xiaoxiao2021-07-12  184

    3.6 增量式前进刚刚接触TDD的人往往为这样的早期版本代码而感到困惑。“我们什么也没有测到(你可能这样想),这只是些硬编码的返回值”;“或者测试太小了,我们只是在各种活动间跳来跳去”。让我来进一步解释。DTSTTCPW:先仿冒再建造回首我刚刚学习极限编程时,Kent Beck在黑板上写下了这个很到位的缩写:DTSTTCPW。它读起来还蛮押韵的;我希望我也能找到那么押韵的一组词。它是Do The Simplest Thing That Could Possibly Work(只做简单够用的东西)的英文缩写。当你只写了几个简单的测试时,通常最简单的事就是仿冒它。LedDriver通过硬编码写到LED地址中的值来仿冒它。一旦你的测试多起来,仿冒就没那么容易了—可能还是真实的实现,或者部分的真实实现更简单。在传统的开发方式中,放入硬编码的值可以是很严重的问题。当这样的捷径方式深埋在实现当中时,它很容易被忘记。这在TDD中却不是什么大问题,因为你还会回到这些地方来。随着你设计出更多的测试,这些弱点就会暴露出来。如果你担心你会忘记,那么在测试列表中记上一笔。当我第一次见到Kent Beck仿冒返回值时,我很困惑。但我自己尝试了一下并发现这样可以工作。正如Kent建议的那样,我确保写了所需的所有测试。在有了相当多的TDD经验后,我有了一个重大的发现:尽管实现离正确还有相当大的差距,但测试是正确的!我教过很多人TDD,并且给他们演示“仿冒它直到做出它”。他们总是问:“那什么时候停止仿冒转而写真实的代码?”我对此简单的首要原则是,一旦去仿冒它比做出它还要麻烦时就做出它。你很快就会明白我说的是什么意思了。保持小而专注的测试有几件事值得我们注意。你可能会想,为什么需要第二个测试用例来测试关闭LED 1呢?要测试关闭LED 1最简单的做法不是给TEST(LedDriver, TurnOnLedOne)加一点代码就可以了吗?但这会让我们的测试缺乏关注。这样就会有两个原因能让该测试失败:LedDriver_TurnOn()坏掉,或者LedDriver_TurnOff()坏掉。在第二个测试中,请注意,并没有对于LedDriver_TurnOn()是否正常工作的检查。(TEST LedDriver,TurnOnLedOne)进行检查,所以我们并不需要在这个以及后面的测试中不断地检查它。刚刚做TDD的程序员往往在每个测试中放入太多东西。这会破坏可读性和关注点。对于一个测试用例中该有多少行断言并无限制,正如对一个函数中该有多少行代码并无限制一样。但是我们要保持测试可读、小巧并且专注。四段测试模式的每一步(建立、执行、验证和拆除)应该在每个测试用例中都清晰可见。当测试变得很大或很不清晰时,它们作为文档的价值就不存在了。当测试变得不清晰,读者会弄不明白它们到底要达到什么目的。让你的测试保持既小又专注,并且给它们起好名字,它们会在今后的几年里回报你。比较理想的情况是一个单一的代码问题只会导致单一的测试失败。顺便说一下,这个理想情况永远不可能达成,但这仍不失为一个好点子。绿了之后就重构TDD中另一个不可分割的部分是重构。重构就是经常清理代码和设计。我们会在第4章中继续开发LedDriver时进行重构。我们还会在第12章中深入讨论重构。唯一可以安全地进行重构的时刻是当所有的测试都通过时。这里进一步强调一下,不要在测试不通过的情况下重构!当有测试失败时,你并没有锁住代码的行为。结构化发生改动,当它与失败的测试纠缠在一起时可能会非常难以重新回到所有测试都通过的状态。让测试保持通过就是保护网,它让重构的杂技安全地进行。现在测试已经通过了,所以让我们来看看我们的新代码里有没有什么问题。当你具备了训练有素的嗅觉时,你会在设计变坏到难以简单改正之前就闻到一些味道。测试代码已经有坏味道了——重复。virtualLeds在每个测试用例中都要创建一遍,每个测试用例都要调用一遍LedDriver_Create()。TEST(LedDriver, LedsOffAfterCreate)还是要有,因为它处理一种特殊的情况。移出在另两个测试中的重复,如下所示:

    测试即文档,应当小心地命名它们。一旦测试通过后,请确保名字能表达测试的意图。

    相关资源:七夕情人节表白HTML源码(两款)

    最新回复(0)