我们如何处理在开发过程中会失败的单元/回归测试?
在软件开发过程中,代码库中可能存在一些已知问题。如果测试编写得当,这些错误将导致回归/单元测试失败。
我们的团队一直在争论如何管理失败的测试:
- 缺点:可能会忘记重新访问已注释掉的测试用例,这意味着缺陷可能会从裂缝中漏出。
- 缺点:由于故障噪声,很难检测何时引入新的缺陷。
我想探讨一下这方面的最佳做法。我个人认为,三态解决方案是确定脚本是否通过的最佳方法。例如,当我们运行脚本时,我们可能会看到以下内容:
- 通过率:75%
- 失败百分比(预期):20%
- 失败百分比(意外):5%
基本上,我们将使用一些元数据标记我们期望失败(由于某些缺陷)的所有测试用例。这样可以确保我们仍可以在测试结束时看到失败结果,但是可以立即知道是否有新的失败,这是我们所不希望的。这似乎占据了上述两个建议的最佳部分。
有人有管理此问题的最佳做法吗?
解决方案
我倾向于使用Ignore属性(使用NUnit)将这些保留在测试运行输出中提到的测试中,因此它是可见的,希望这意味着我们不会忘记它。考虑在"忽略"消息中添加问题/票证ID。这样一来,当基本问题被认为已经成熟时,就可以解决该问题,最好立即修复失败的测试,但是有时候,小错误必须等到正确的时机。
我考虑过Explicit属性,该属性具有无需重新编译即可运行的优点,但是它不需要" reason"参数,并且在我们运行的NUnit版本中,测试不会显示在输出中为unrun。
我会保留测试用例。以我的经验,用类似
// TODO: fix test case
类似于:
// HAHA: you'll never revisit me
认真地说,随着我们越来越接近发行,重新审视代码中的TODO的愿望会逐渐减弱,尤其是在单元测试之类的情况下,因为我们正专注于修复代码的其他部分。
将测试留在"三态"解决方案中。但是,我强烈建议尽快解决这些问题。我经常提醒的问题是,人们看到他们之后,他们往往会掩盖他们并说:"哦,是的,我们一直都在犯这些错误……"
恰当的例子-在我们的某些代码中,我们引入了"可跳过的断言"的概念-那里的断言可以让我们知道存在问题,但允许我们的测试人员将其移到其余代码中。我们发现QA开始说诸如"哦,是的,我们一直都坚持这一主张,并被告知这是可以跳过的"之类的东西,并且没有报告错误。
我想我建议的是还有另一种选择,它可以立即修复测试用例中发现的错误。可能有实际的原因不这样做,但是从长远来看,现在养成这种习惯可能会更加有益。
我们执行了以下操作:在测试上建立层次结构。
示例:我们必须测试3件事。
- 测试登录名(登录,获取用户名,获取"上次登录日期"或者类似的信息等)
- 测试数据库检索(搜索给定的" schnitzelmitkartoffelsalat"-标签,搜索最新标签)
- 测试Web服务(连接,获取版本号,检索简单数据,检索详细数据,更改数据)
每个测试点都有子点,如括号中所述。我们将这些层次划分。拿最后一个例子:
3. Connect to a web service ... 3.1. Get the version number ... 3.2. Data: 3.2.1. Get the version number 3.2.2. Retrieve simple data 3.2.3. Retrieve detailed data 3.2.4. Change data
如果某个点失败(在显影时),则给出一个确切的错误消息。 IE。 3.2.2. 失败的。这样,测试单元将不会执行3.2.3的测试。和3.2.4. 。这样,我们将收到一条(准确的)错误消息:" 3.2.2失败"。因此,让程序员(首先)解决该问题而不处理3.2.3. 和3.2.4. 因为这行不通。
这在很大程度上有助于弄清问题并弄清楚一开始必须做什么。
我认为我们需要一个从代码库生成" TODO"注释的TODO监视程序。 TODO是测试元数据。这是已知故障消息前面的一行,非常容易关联。
TODO的很好。使用它们。主动管理它们,方法是定期定期将它们实际放入积压中。
我通常在Perl中工作,Perl的Test :: *模块允许我们插入TODO块:
TODO: { local $TODO = "This has not been implemented yet." # Tests expected to fail go here }
在测试运行的详细输出中,$ TODO中的消息会添加到TODO块中每个测试的通过/失败报告中,以解释为什么它会失败。对于测试结果的摘要,所有TODO测试都被视为已成功,但是,如果有任何实际返回成功的结果,则摘要还将对这些结果进行累加并报告意外成功的测试数量。
因此,我的建议是找到一种具有类似功能的测试工具。 (或者,即使正在测试的代码是另一种语言,也可以仅使用Perl进行测试...)
Joel的"改进代码的12个步骤"中的#5在编写新代码之前修复了错误:
When you have a bug in your code that you see the first time you try to run it, you will be able to fix it in no time at all, because all the code is still fresh in your mind. If you find a bug in some code that you wrote a few days ago, it will take you a while to hunt it down, but when you reread the code you wrote, you'll remember everything and you'll be able to fix the bug in a reasonable amount of time. But if you find a bug in code that you wrote a few months ago, you'll probably have forgotten a lot of things about that code, and it's much harder to fix. By that time you may be fixing somebody else's code, and they may be in Aruba on vacation, in which case, fixing the bug is like science: you have to be slow, methodical, and meticulous, and you can't be sure how long it will take to discover the cure. And if you find a bug in code that has already shipped, you're going to incur incredible expense getting it fixed.
但是,如果我们真的想忽略失败的测试,请在使用的任何测试框架中使用[Ignore]属性或者等效属性。在MbUnit的HTML输出中,被忽略的测试以黄色显示,而失败的测试则以红色显示。这使我们可以轻松地注意到一个新失败的测试,但是我们不会忘记已知失败的测试。
立即修复该错误。
如果太复杂而无法立即执行,那么对于单元测试而言,它可能太大了。
丢失单元测试,并将缺陷放入错误数据库中。这样,它就具有可见性,可以进行优先级排序等。