TDD周期的第一部分是选择失败的测试。我想开始一个关于这个选择过程的社区维基。
有时选择开始的测试是显而易见的,从低悬的果实开始。例如,在编写解析器时,一个简单的测试就是不处理任何输入的测试:
def testEmptyInput():
result = parser.parse("")
assertNullResult(result)
有些测试很容易通过,只需要很少的实现代码,如上例所示。
其他测试需要复杂的实现代码板才能通过,我感觉我没有做过“最容易让测试通过的事情”。在这一点上,我停止尝试通过这个测试,并选择一个新的测试试图通过,希望它将揭示有问题的实现更容易的实现。
我想探讨这些简单而具有挑战性的测试的一些特性,它们如何影响测试用例的选择和排序。
测试选择如何与自上而下和自下而上策略相关?任何人都可以推荐与TDD相关的解决这些策略的文章吗?
答案 0 :(得分:2)
我首先锚定代码中最有价值的行为。
例如,如果它是验证器,我首先要确保它说有效对象是有价值的。现在我们可以展示代码,培训用户不要做愚蠢的事情等等 - 即使验证器永远不会得到进一步实施。之后,我开始添加边缘案例,首先是最危险的验证错误。
如果我从一个解析器开始,而不是从一个空字符串开始,我可能会从一些典型但简单的东西开始,我想解析一些东西,我想从中解决这个问题。对我来说,单元测试更像是我将如何使用代码的示例。
我也遵循BDD命名测试should
的做法 - 所以对于你的例子,我有shouldReturnNullIfTheInputIsEmpty()
。这有助于我确定代码应该做的下一个最重要的事情。
这也与BDD的“从外到内”有关。以下是我撰写的一些可能有用的博文:Pixie Driven Development和Bug Driven Development。 Bug Driven Development帮助我弄清楚我需要的下一部分系统级功能,然后帮助我找到下一个单元测试。
希望这给你一个稍微不同的视角,无论如何 - 祝你好运!
答案 1 :(得分:1)
首先,我将选择一个简单的典型案例并为其编写测试。
在我编写实现时,我会注意我的代码处理错误的极端情况。然后我会为这些案件编写测试。
否则我会寻找有问题的功能应该做的事情,但不会。