是否可以编写涵盖所有内容的单元测试?

时间:2017-07-17 04:41:32

标签: unit-testing language-agnostic

假设我有一个功能

$folder_path = read-host "Enter the  folder path without space"
$file = gci $folder_path -Recurse | ? {-not $_.psiscontainer} 
$file | group -property extension | % {if(!(test-path(join-path $folder_path -child $_.name.replace('.','')))){new-item -type directory $(join-path $folder_path -child $_.name.replace('.','')).toupper()}}
$file | % {  move-item $_.fullname -destination $(join-path $folder_path -child $_.extension.replace(".",""))}
$a = Get-ChildItem $folder_path -recurse | Where-Object {$_.PSIsContainer -eq $True}
$a | Where-Object {$_.GetFiles().Count -eq 0} | Remove-Item -Force

理想情况下,您希望编写2 ^ 32 - 1个测试用例来覆盖INT_MIN到INT_MAX?当然这不实用。

为了让生活更轻松,我们为

编写测试用例
  • x< 10,测试x = 9期望为真
  • x == 10,test x = 10 expect false
  • x> 10,测试x = 11期望错误

这些测试用例很好但并不涵盖所有情况。假设有一天有人将该功能修改为

function (int x) {
  if (x < 10) return true;
  return false;
}

他将进行测试并实现所有测试通过。我们如何确保我们覆盖每个场地而不会走极端。我正在描述这个问题的关键词吗?

2 个答案:

答案 0 :(得分:2)

部分答案是部分答案,因为你提出问题的方式。

评论

  

是否可以编写涵盖所有内容的单元测试?

否。即使在您的示例中,您也将测试用例限制为2^32,但如果将代码移至64位系统,然后有人使用{{1}添加一行,该怎么办?或者别的什么。

此外,您的问题向我表明您正在考虑使用动态代码的静态测试用例,例如:代码是动态的,因为它由程序员随时间改变,这并不意味着代码动态修改。您应该考虑使用动态代码的动态测试用例。

最后你没有注意到它是白色,灰色还是黑盒测试。

答案

让工具分析代码并生成测试数据。

请参阅:A Survey on Automatic Test Data Generation

您还询问了搜索的关键词。

以下是谷歌搜索我发现的价值:

code analysis automated test generation survey

相关

我自己从未使用过这些测试用例工具之一,因为我使用Prolog DCG来生成我的测试用例,目前我正在做的项目在大约两分钟内生成了数百万个测试用例并在几个测试中测试它们分钟。一些失败的测试用例我永远不会想到我自己,所以这可能被一些人视为过度杀戮,但它确实有效。

由于许多人不知道Prolog DCG这里使用的是与Eric Lippert一起使用C#和LINQ解释的类似方式,Every Binary Tree There Is

答案 1 :(得分:0)

不,目前还没有针对此的通用算法,不涉及某种非常密集的计算(例如测试很多和很多情况),但是你可以用他们将拥有的方式编写你的单元测试在改变方法的情况下失败的可能性更高。例如,在给出的答案中,写一个x = 10的测试。对于其他两种情况,首先选择11和int.Max之间的几个随机数并测试它们。然后测试int.Min和9之间的几个随机数。在你描述的修改之后,测试不会必然失败,但是如果你刚刚修改它将失败的可能性更大硬编码的价值。

另外,正如@GuyCoder在他出色的回答中指出的那样,即使你做了尝试做类似的事情,要证明没有可能的变化是非常困难的(或不可能的)会破坏你的考试的方法。

另外,请记住,没有任何一种测试自动化(包括单元测试)是一种万无一失的测试方法;即使在理想条件下,您通常也不能100%证明您的程序是正确的。请记住,几乎所有软件测试方法都是基本的经验方法,经验方法无法真正实现100%的确定性。 (他们可以获得很大的确定性;事实上,许多科学论文达到95%的确定性或更高 - 有时更高 - 所以在这样的情况下,差异可能不是那么重要) 。例如,即使你有100%的代码覆盖率,你怎么知道测试中的某个地方没有错误?你打算为测试编写测试吗? (这可能导致turtles all the way down类型的情况。)

如果你想真正了解它并且你买入David Hume,你真的不能100%肯定基于经验测试的东西;每次运行测试都已经过去的事实并不意味着它将来会继续通过。我离题了。

如果您有兴趣,formal verification会研究演绎软件(或者至少是软件的某些方面)是否正确的方法。请注意,与此相关的主要问题是,对于任何复杂的完整系统的程序进行形式验证往往非常困难或不可能,特别是如果您使用未经正式验证的第三方库。 (这些以及首先学习技术的困难,是正式验证在学术界和某些非常狭窄的行业应用之外尚未真正起飞的一些主要原因。)

最后一点:软件附带错误。您很难找到任何复杂系统,该系统在发布时100%无缺陷。正如我上面提到的,目前还没有一种技术可以保证您的测试能够找到所有的错误(如果你能找到一个你将成为非常富有的人),那么最多部分你必须依靠统计测量来了解你是否已经进行了充分的测试。

TL; DR 不,您不能,即使您仍然无法100%确定您的软件是正确的(您的测试中可能存在错误,例)。在可预见的将来,您的单元测试用例也需要维护。不过,您可以将测试编写为 more 对变更具有弹性。