检查失败的单元测试的价值是什么?


13

尽管有阻止执行单元测试的方法,但是检查失败的单元测试的价值是什么?

我将使用一个简单的示例:区分大小写。当前代码区分大小写。该方法的有效输入是“ Cat”,它将返回Animal.Cat的枚举。但是,该方法的所需功能不应区分大小写。因此,如果所描述的方法通过“ cat”传递,则它可能返回类似于Animal.Null而不是Animal.Cat的内容,并且单元测试将失败。尽管只需进行简单的代码更改即可完成此工作,但更复杂的问题可能需要花费数周的时间才能解决,但是使用单元测试来确定错误可能不是那么复杂。

当前正在分析的应用程序具有4年有效的代码。但是,最近有关单元测试的讨论发现了代码中的缺陷。有些只需要显式的实现文档(例如是否区分大小写),或者不根据当前调用方式执行该错误的代码。但是可以执行特定的场景来创建单元测试,这将导致错误被看到并且是有效的输入。

在有人能够修正该代码之前,检查行使该错误的单元测试的价值是什么?

是否应该使用忽略,优先级,类别等标记此单元测试,以根据执行的测试确定构建是否成功?最终,一旦有人对其进行了修复,就应该创建单元测试来执行代码。

一方面,它表明已识别的错误尚未修复。另一方面,在日志中可能会出现数百个失败的单元测试,并且很难找出应该失败的测试与由于代码检入而导致的失败。


这是增加测试覆盖率的一种方法。
JeffO '16

如果您已经在努力编写单元测试,那么当您决定解决该问题时,为什么还要重写它呢?仅因为它已签入,并不意味着它必须在套件中运行。(您可以为“已知问题”创建一个类别,并将这些测试视为待办事项/待办事项列表。)
Caleb

Answers:


17

不喜欢检入损坏的单元测试,因为它们会产生不必要的噪音。每次单元测试后,我都必须检查所有失败的问题(红色)。是红色的,是因为有新问题,还是因为有旧的待解决问题。如果单元测试超过20个,这是不可行的。

相反,我用

  • [Ignore("Reason")]使结果呈黄色
  • throw new NotImplementedException()使结果变灰

注意:我正在将NUnit用于.net。我不确定其他单元测试框架中是否存在“灰色”功能。

因此,我喜欢单元测试结果的以下含义。

  • 绿色:全部完成
  • 灰色:需要完成的计划中的新功能,但优先级较低
  • 黄色:尚未修复的错误。应该尽快修复
  • 红色:新错误。应立即修复

可以检入除“红色”以外的所有内容。

要回答这个问题:检入“红色失败的测试”的危害大于价值,但检入“黄色忽略的测试”或“灰色-未实施测试”可能作为待办事项列表有用。


我看到的这种方法的问题是,被忽略的测试可能永远不会修复。您也可以只删除整个测试代码,有什么区别(我在这里有点自大)
Lovis

4
will probably never be fixed是否要在自动测试中使用efford是一个政治决定。使用“忽略的测试”,您就有机会修复它们。扔掉“被忽略的测试”意味着“逐渐放弃自动化测试,直到没有更多了”
k3b

8

我不会假装这是行业标准,但是我签入残破的测试是为了提醒我或我的其他项目成员代码或单元测试本身仍然存在问题。

我想要考虑的一件事是您的开发策略是否允许失败的测试而不会造成损失。我有一个朋友在一家商店进行测试驱动的开发工作,所以他们总是以失败的测试开始...


5
但是,您切勿签入失败的测试,因为构建服务器不应构建测试失败的项目。
CaffGeek 2011年

@Chad:构建和测试是一个自动化步骤的两个独立部分。构建可确保所有内容都能编译。测试确保生成的结果有效。我对这个问题的解释不是,“我应该检入未编译的代码吗?” 相反,它是:“我应该检查知道会失败的测试吗?”
unholysampler 2011年

1
我只是想考虑一点,一些连续集成构建服务器运行测试,如果它们失败,则不会部署它们。正确地,就好像构建失败了,代码也会失败,并且部署已知已损坏的产品毫无意义。
CaffGeek 2011年

@Chad:是的,我完全忘记了CI服务器。那绝对是要考虑的一点。也有必要阐明“破损”测试的含义;它们只是普通的“不良”测试,还是由于API有所更改而导致测试失败?
Tieson T. 2011年

这个问题应该更清楚了。测试应该编译,但是预期结果将失败。

6

失败的单元测试使开发团队可以看到必须做什么才能符合约定的规格。

简而言之,单元测试失败会给团队一个“待办事项”清单。

因此,失败的单元测试比根本没有单元测试好得多。*
缺少单元测试会使开发团队陷入困境。规格必须反复手动确认。

[*提供单元测试实际上可以测试有用的东西。]


2
有更好的方法来维护待办事项列表,例如白板,待办事项应用程序或问题跟踪系统。如果您希望测试套件始终完全通过测试,那么使用它会容易得多,并且出现的任何测试失败都是立即解决的新问题。
bdsl

6

单元测试的目的是断言系统的预期行为,而不是记录缺陷。如果我们使用单元测试来记录缺陷,那么它们对断言预期行为的实用性就会降低。问题“为什么该测试失败的答案”?这不是一个简单的“哦,有些东西我没想到会被破坏。” 测试失败是预期的还是意外的已变得未知。

这是《有效使用旧版代码》第13章开头的一段:

自动化的单元测试是一个非常重要的工具,但至少不是直接用于错误查找。通常,自动化测试应指定一个我们想要实现或试图保留已经存在的行为的目标。在自然的开发流程中,指定的测试成为保留的测试。您会发现错误,但通常不会在第一次运行测试时发现。当您更改意外行为时,会在以后的运行中发现错误。


3

但是破损的那些可以识别新项目中的错误,因此而得名。这样一来,您可以看到它们应该损坏...当它们被固定时,它们将变成绿色,然后移入正常的测试套件中。

注意:如果您的构建服务器阻止签入破坏了该构建,则必须将该项目设置为不在构建服务器上构建(假设您将一个损坏的构建定义为不通过所有测试的构建)


+1尽管没有答案是否可以签入,但有一个重要的论点:构建服务器
k3b

我宁愿使用属性来标记这样的测试,而不是将其移动到单独的项目中。
CodesInChaos

2

单元测试除了功能的成功案例外,还应该测试错误案例。函数应明确拒绝错误的输入,或应具有文档说明什么输入被认为是有效的。

如果您的功能不执行上述任何一项操作,则说明它是一个错误,您应该有一种记录其存在的方法。创建一个演示此问题的单元测试是实现此目的的一种方法。提交错误凭单是另一种选择。

单元测试的重点不是100%成功,重点是查找并修复代码中的错误。不进行测试是获得100%成功的一种简单方法,但这对项目不是很有好处。


哇...“单元测试的重点不是100%成功”,您是说他们并不需要全部通过!?
CaffGeek 2011年

2
@Chad:关键是最好让您知道会失败的测试,但是这是一个真实的问题,而不是没有测试,这样您可以在每晚构建/测试结束时使用绿色的复选标记。
unholysampler 2011年

8
@unholysampler,永远不会有损坏的测试,除非将它们清楚地标记为“应该”中断(因为在另一个项目中)。否则,它们会变成噪音,您不知道应该通过的测试何时破裂。它完全
违反

2
@乍得:我认为这正在进入定义的语义。在OP的基础上,听起来他正在谈论创建一个有效的测试以测试bug的方法。但是,该错误的优先级较低,不太可能立即修复。您就是提出“持续集成”的人,该集成对自动化过程提出了更严格的限制。
unholysampler 2011年

4
@ unholysampler,CI或没有CI,关键是,当您运行测试并习惯于看到一些红灯时,您已经习惯了它。 因此,当绿色的东西变成红色时……您怎么知道?! 这是一种可怕的做法,也是许多组织无法接受测试的原因之一。
CaffGeek 2011年

1

记录每个失败的错误,并在测试结果中注明。然后,如果您一起采取行动并修复了错误,则测试通过,然后将其从测试结果中删除。永远不要忽视问题。


-3

我如何看待TDD对未完成的代码实施测试,是首先使用[ExpectedException]属性或类似属性编写测试。这应该首先通过,因为不完整的代码中将没有任何逻辑,并在其中编写引发新的Exception()代码。尽管通过异常是错误的,但这至少会使测试最初通过并适合签入。我们可能会忘记被忽略的测试,但肯定会整理或填充不完整的代码。当我们这样做时,原本预期会发生故障的相应测试将立即开始失败,并警告您修复它。这可能涉及对测试进行少许更改以摆脱ExpectException,而是执行真正的断言。CI,开发人员,测试人员和客户都感到高兴和双赢?


1
这不能回答问题。它不问什么是TDD,以及为什么要测试预期的异常。
Andy Wiesendanger
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.