重要的是我试图通过先编写所有测试然后创建代码来做一些 TDD。
问题是“首先编写我所有的测试”最强调不是“做一些 TDD”。测试驱动开发包含大量“红-绿-重构”循环的小重复:
- 将单元测试添加到测试套件,运行它并观察它失败(红色)
- 将足够的代码添加到被测系统以使所有测试通过(绿色)
- 改进被测系统的设计(通常通过删除重复),同时保持所有测试通过(重构)
如果您预先编写了整个庞大的测试套件,您将永远花费大量时间尝试进入“绿色”(所有测试通过)状态。
但是,该应用程序将无法编译,因为我的任何对象或方法都不存在。
这是任何编译语言的典型特征。这本身不是 TDD 问题。这意味着,为了观察新的测试失败,您可能必须为您当前正在处理的任何功能编写一个最小的存根,以使编译器满意。
例如,我可能会编写这个测试(使用 NUnit):
[Test]
public void DefaultGreetingIsHelloWorld()
{
WorldGreeter target = new WorldGreeter();
string expected = "Hello, world!";
string actual = target.Greet();
Assert.AreEqual(expected, actual);
}
然后我必须编写这么多代码来编译应用程序并且测试失败:
public class WorldGreeter
{
public string Greet()
{
return String.Empty;
}
}
一旦我获得了构建解决方案并且我看到了一个失败的测试,我可以添加代码以使第一个测试通过:
public string Greet()
{
return "Hello, world!";
}
一旦所有测试都通过,我就可以查看被测系统,看看可以做些什么来改进设计。但是,对于 TDD 规则来说,在进行重构之前必须经历“红色”和“绿色”这两个步骤。
我认为它的全部意义在于,当您开发测试时,您可以开始看到重复等,以便您可以在编写单行代码之前进行重构。
Martin Fowler 将重构定义为“一种用于重构现有代码体的规范技术,在不改变其外部行为的情况下改变其内部结构”(强调)。如果你没有写过一行代码,就没有什么可重构的了。
所以问题是,有没有办法做到这一点,还是我做错了?
如果你想做 TDD,那么,是的,我担心你做错了。您很可能能够交付出色的代码来做您正在做的事情,但这不是 TDD;这是否是一个问题由您自己决定。