现在,它真的很棒吗?它不是有时似乎是一个完全的时间损失,这只是使维修更困难的效果吗?
例如,假设我有一个方法DisplayBooks()填充数据库中的书籍列表。产品要求告诉,如果在商店中有超过一百本书,则必须仅显示一百个书。
因此,使用TDD,
>我将首先做一个单元测试BooksLimit(),它将在数据库中保存两百本书,调用DisplayBooks(),并做一个Assert.AreEqual(100,DisplayedBooks.Count)。
>然后我会测试如果失败,
>然后我将通过将结果的限制设置为100来更改DisplayBooks()
>最后,我将重新运行测试,看看是否成功。
嗯,是不是更容易直接去第三步,从来没有使BooksLimit()单元测试吗?而不是更敏捷,当需求从100到200的书限制,只更改一个字符,而不是更改测试,运行测试,以检查它是否失败,更改代码和运行测试,以检查它是否成功?
注意:我们假设代码是完全记录的。否则,有人可能会说,他们是正确的,做全单元测试将有助于理解缺少文档的代码。事实上,有一个BooksLimit()单元测试将非常清楚地显示有最大数量的书籍要显示,并且这个最大数量是100.步入非单位测试代码将是更加困难,因为这样可以通过对(int bookIndex = 0; bookIndex <100; ...或foreach ... if(count> = 100)break;
Well,isn’t it much more easier to go directly to the third step,and do never make BooksLimit() unit test at all?
是的…如果你不花任何时间写测试,你将花更少的时间编写测试。您的项目可能需要更长的时间,因为您将花费大量的时间调试,但也许这更容易向您的经理解释?如果是这样的情况…得到一份新工作!测试对于提高您对软件的信心至关重要。
当你有很多代码时,单元测试给出最大的价值。它很容易调试一个简单的作业分配使用几个类,没有单元测试。一旦你走出了世界,你在数百万行的代码库工作 – 你会需要它。你根本不能单步调试器通过一切。你根本不能理解一切。你需要知道你依赖的类工作。你需要知道,如果有人说“我只是要改变行为,因为我需要它”,但他们忘记了有另外两百个依赖于这种行为的用途。单元测试有助于防止这种情况。
关于使维修更难:不管!我不能把这么大。
如果你是唯一一个曾经在你的项目上工作的人,那么是的,你可能会这样想。但这是疯狂的谈话!尝试在没有单元测试的情况下达到30k线路项目的速度。尝试添加需要对没有单元测试的代码进行重大更改的功能。没有信心,你不打破其他工程师做出的隐性假设。对于维护者(或现有项目的新开发者),单元测试是关键。我倾向于单元测试的文档,行为,假设,告诉我,当我破碎的东西(我认为是无关的)。有时一个写得不好的API的测试写得不好,可能是一个噩梦,因为测试吸引了你所有的时间。最终你会想重构这个代码并解决这个问题,但你的用户会感谢你的 – 你的API将更容易使用,因为它。
关于覆盖范围的说明:
对我来说,这不是100%的测试覆盖率。 100%覆盖没有找到所有的错误,考虑一个带有两个if语句的函数:
// Will return a number less than or equal to 3 int Bar(bool cond1,bool cond2) { int b; if (cond1) { b++; } else { b+=2; } if (cond2) { b+=2; } else { b++; } }
现在考虑我写一个测试,测试:
EXPECT_EQ(3,Bar(true,true)); EXPECT_EQ(3,Bar(false,false));
这是100%的覆盖。这也是一个不符合合同的函数 – Bar(false,true);失败,因为它返回4.所以“完全覆盖”不是最终目标。
老实说,我会跳过对BooksLimit()的测试。它返回一个常量,所以它可能不值得的时间来写它们(并且应该在编写DisplayBooks()时测试)。当某人决定(不正确地)从货架尺寸计算出该限制,并且它不再满足我们的要求时,我可能会很伤心。我以前被“不值得测试”烧了。去年我写了一些代码,我对我的同事说:“这个类主要是数据,它不需要测试”。它有一个方法。它有一个错误。它去生产。它在半夜呼唤我们。我觉得很蠢。所以我写的测试。然后,我深思熟虑了,什么代码构成“不值得测试”。没有太多。
所以,是的,你可以跳过一些测试。 100%的测试覆盖面是伟大的,但它并不神奇地意味着你的软件是完美的。这一切都归结于面对变化的信心。
如果我把类A,类B和类C在一起,我发现一些不工作,我想花时间调试所有三个?不,我想知道A和B已经满足他们的合同(通过单元测试),我在C类的新代码可能是破碎。所以我单元测试它。我怎么知道它坏了,如果我不单元测试?点击一些按钮并尝试新的代码?这是好的,但不够。一旦您的程序扩展,就不可能重新运行所有的手动测试,以检查一切正常。这就是为什么单元测试的人通常也自动运行他们的测试。告诉我“通过”或“失败”,不要告诉我“输出是…”。
好吧,去写一些更多的测试…