然而,我的问题是:在开始新项目时何时引入单元测试?按照TDD的精神,项目的第一行代码可能应该是一个单元测试。然而,无论我有多么喜欢TDD给我的那种模糊感觉,当你什么都没有的时候,我经常发现从一开始就进行单元测试很困难。通常情况下,我发现在看到项目将要走向何方时,不测试而编码更容易,“作弊”并引入测试。
人们对此有什么看法?在开始新项目时应该何时引入单元测试?
你应该能够从单元测试开始。如果你发现很难做到这一点,那么在我的经验中,你可能没有将要求分解为其原子位。
在我看来,第一个可交付成果应该具有80%以上的测试覆盖率,并且第一个可交付成果应该在第一(或第二)次迭代的末尾完成。
除此之外,如何与TDD哲学保持一致是个人喜好的问题。
你必须真正有兴趣帮助对方,并利用一个教学机会:
一个学生被TDD大师每天责骂。他说:“为什么你不先进行测试驱动开发?你是一个开发者。你应该进行开发者测试!”
大师用卷起来的报纸打了学生一年,每天像这样责骂他,直到有一天,一个愉快的极限编程教练出现了。
极限编程教练听到开发者说:“我在这个该死的功能上挣扎,但我做不好。”
教练微笑着说:“再给我展示一下你是怎么做到的…”
学生又设置了例子并运行了失败的代码。
“当我按下这个按钮并将滑动条移动到4时,它应该输出42而不是41!你认为我该怎么办?”
愉快的XP教练又微笑了一次(他经常这样),说:“再做一遍,但这次让我来打字…”
在你意识到之前,学生和教练已经一起编写了一个TDD测试,但由于学生有动力完成他的工作,所以他忘记抵制,并分散了注意力,没有进行关于敏捷哲学的元讨论。
然后学生说:“啊哈!我懂了。所以这就是我们写单元测试的原因”
… 在那一刻,学生得到了启迪。大功告成!
;-)
我通常从最重要的特性开始,采用自外向内的方法逐步深入。这通常意味着从一些UI开始。
我的做法是先创建所需的UI。由于我们通常无法使用TDD开发UI,因此我只需使用所选技术创建View即可。没有测试,但我会将UI与某个API连接起来(最好使用声明式数据绑定),这时测试开始了。
所以我经常编写一个不带测试的Humble Object,但一旦我开始编写具有大于1个环路复杂度的代码,我就开始先编写单元测试。
对于库来说,这意味着有时我甚至会在创建SUT库之前创建测试套件库。
class HelloWorld
{
int value;
int getValue() { return value; }
}
并且没有任何测试。但是一旦我这样做:
class HelloWorld
{
int value;
int getValue() { return value; }
int doSomething() { blah blah blah }
}
我写了一个测试用例。
我的编程模式通常是先开始编写一个新项目,一旦我有了一个带有一定功能的类,我就会立即为其创建一个单元测试。换句话说,我很早就将单元测试项目作为解决方案的一部分引入。
(目前我并没有实践TDD,但我确实看到了它的好处)。
我建议从编写第一行代码时就开始使用 TDD。
TDD 对我来说是一种“设计”方法,可以帮助我创建干净且可工作的面向对象的代码。当我编写测试单元类时,实际上是在描述我想要与要构建的对象进行的“对话”。
因此,在我不清楚代码应该做什么时,它确实有助于我完成它。
正如您所解释的那样,副作用也是构建一个优秀的测试工具,它是构建应用程序的镜像。