我正试图了解TDD方法并且遇到了 - 我认为是 - 一个鸡蛋问题:如果错误修复涉及更改方法的签名该怎么办。
考虑以下方法签名:
string RemoveTokenFromString (string delimited, string token)
顾名思义,此方法从token
中删除delimited
的所有实例,并返回结果字符串。
我后来发现这个方法有一个错误(例如从字符串中删除了错误的位)。因此,我编写了一个测试用例,描述了发生错误的场景,并确保测试失败。
修复bug时,我发现该方法需要更多信息才能正常工作 - 这些信息只能作为参数发送(被测方法是静态类的一部分)
那我该怎么办?如果我修复了这个bug,这迫使我改变单元测试 - 这是'正确的'TDD方法吗?
答案 0 :(得分:7)
你已陷入TDD中最危险的陷阱:你认为TDD是关于测试的,但事实并非如此。但是,由于TDD中的所有术语都与测试有关,因此很容易陷入该陷阱。这就是BDD被发明的原因:它本质上是TDD,但没有令人困惑的术语。
在TDD中,测试不是真正的测试,它们就是例子。断言并不是真正的断言,它们是期望。而且你不是在处理单位,而是处理行为。 BDD只是称他们为。 (注意:BDD自最初发明以来已经发展,现在它包含了不属于TDD的东西,但最初的意图只是“很多人做TDD错误,所以用不同的词来帮助他们做正确的事”。 )
无论如何,如果你认为测试不是一个测试,而是一个关于该方法应该如何工作的行为示例,那么显而易见的是,当您对预期行为有更好的理解时,删除或更改测试不是只有TDD允许,它才是唯一正确的选择!始终牢记这一点!
答案 1 :(得分:6)
当您发现设备的预期行为发生变化时,对您的测试进行轰炸绝对没有错。
//Up front
[Test]
public void should_remove_correct_token_from_string()
{
var text = "do.it.correctly..";
var expected = "doitcorrectly";
Assert.AreEqual(StaticClass.RemoveTokenFromString(text, "."), expected);
}
//After finding that it doesn't do the right thing
//Delete the old test and *design* a new function that
//Does what you want through a new test
//Remember TDD is about design, not testing!
[Test]
public void should_remove_correct_token_from_string()
{
var text = "do.it.correctly..";
var expected = "doitcorrectly";
Assert.AreEqual(
StaticClass.RemoveTokenFromString(
text,
".",
System.Text.Encoding.UTF8), expected);
}
//This will force you to add a new parameter to your function
//Obviously now, there are edge cases to deal with your new parameter etc.
//So more test are required to further design your new function
答案 2 :(得分:4)
保持简单。
如果您的单元测试错误或已过时,则必须重写它。如果您的规格发生变化,或某些规格不再相关,则您的单元测试必须反映出来。
红色,绿色,重构也适用于您的单元测试,而不仅仅是您正在测试的代码。
答案 3 :(得分:2)
有一个名为Add Parameter的重构可以提供帮助。
如果您的语言支持method overloading,您可以先使用新参数创建新功能,复制现有功能的主体并解决问题。
然后,当问题得到解决时,您可以逐个修改所有测试以调用新方法。最后你可以删除旧方法。
使用不支持方法重载的语言,创建一个具有不同名称的新函数,在该新函数中复制现有函数的主体,让现有函数调用新函数,可能具有虚拟值新参数。那么你可以通过所有测试。让您的旧测试逐个调用新函数。当不再使用旧方法时,可以删除它并重命名新函数。
这有点过程广泛,但我认为这个是遵循red-green-refactor的TDD方式。
如果可用,参数的默认值也可以提供帮助。
答案 4 :(得分:1)
红色,绿色,重构。
无论你做什么,你首先要进入一个状态,你有一个编译但失败的测试用例,可以重现bug。然后,您可以继续将参数添加到测试和实现中,但不执行任何操作,因此您仍然可以使用Red。
答案 5 :(得分:1)
我会说不要担心'正确'/'正确'的方式......无论如何帮助你更快地接近解决方案。
如果您发现需要接受额外的参数,
只有在添加新参数会导致数以万计的编译错误的情况下,我才会建议 - 按照小步骤进行操作......你不想更新整个源代码库,然后才发现你真的不需要第三个参数或者你需要第四个...时间丢失。因此,在更新所有引用之前,请使用该方法的新版本“正常工作”。 (正如菲利普所说)
答案 6 :(得分:0)
如果方法没有正确地完成工作,则需要修复它,如果修复需要更改签名,那么注意到错误。根据TDD,您首先编写测试用例,这肯定会失败,然后您编写方法来满足测试。按照这种方法,如果测试中的方法调用需要一个参数来使其起作用,那么你需要这样做。