测试一下?

时间:2009-02-03 13:36:43

标签: unit-testing automated-tests

我主要把时间花在win32和.NET应用程序的自动化测试上,这需要大约30%的时间来编写,70%用于维护。我们一直在研究减少维护时间的方法,并且已经转移到可重用的测试库,该库涵盖了我们软件的大部分关键组件。此外,我们正在进行一些工作,以使我们的图书馆进入我们可以使用keyword based testing的状态。

我一直在考虑对我们的测试库进行单元测试,但我想知道它是否值得花时间。我是软件单元测试的坚定支持者,但我不确定如何处理测试代码。

您认为自动化Gui测试库应该进行单元测试吗?或者只是浪费时间?

13 个答案:

答案 0 :(得分:11)

首先,我发现将单元测试视为“可执行规范”而非测试非常有用。我写下了我想要的代码,然后实现它。我从编写单元测试中获得的大部分好处是它们推动了实现过程并集中思考。它们可以重复使用以测试我的代码这一事实几乎是一个幸福的巧合。

测试测试似乎只是一种解决问题而不是解决问题的方法。谁将测试测试测试的测试? TDD用来确保测试实际有用的“技巧”是首先让它们失败。这也许你可以在这里使用。编写测试,看到它失败,然后修复代码。

答案 1 :(得分:9)

我认为你不应该对你的单元测试进行单元测试。

但是,如果你已经编写了自己的测试库,有自定义断言,键盘控制器,按钮测试器或者什么,那么是的。您应该编写单元测试来验证它们是否都按预期工作。

例如,NUnit库经过单元测试。

答案 2 :(得分:5)

理论上,软件,因此应进行单元测试。如果您正在推出自己的单元测试库,尤其是您需要在进行单元测试时进行单元测试。

但是,主软件系统的实际单元测试不应该增长到足以进行单元测试。如果它们非常复杂以至于它们需要进行单元测试,那么您需要对软件进行一些认真的重构,并注意简化单元测试。

答案 3 :(得分:5)

您可能需要查看Who tests the tests

  

简短的回答是代码测试测试,测试测试代码。

     

咦?

     

测试原子钟
  让我先来一个类比。假设你是   和原子钟一起旅行。你怎么知道时钟是   校准正确吗?

     

一种方法是向你的邻居询问一个原子钟(因为每个人都是   带上一个)并比较两者。如果他们都报告相同   时间,那么你对他们都是正确的充满信心。

     

如果它们不同,那么你就知道其中一个是错误的。

     

所以在这种情况下,如果你问的唯一问题是,“是我的   时钟给出正确的时间?“,那么你真的需要第三个时钟吗?   测试第二个时钟和第四个时钟来测试第三个时钟?不是   所有。 Stack Overflow避免了!

IMPO:这是你需要多少时间和你想拥有多少质量之间的权衡。

  • 如果我要使用自制的测试哈纳斯,我会在时间允许的情况下进行测试。
  • 如果它是我正在使用的第三方工具,我希望供应商对其进行测试。

答案 4 :(得分:2)

你真的没有理由/不应该对你的图书馆进行单元测试。有些部件可能太难以进行正确的单元测试,但大部分部件可能都经过单元测试而没有特别的问题。

实际上,对这种代码进行单元测试可能特别有用,因为您希望它既可靠又可重复使用。

答案 5 :(得分:2)

测试测试代码,代码测试测试。当你以两种不同的方式表达相同的意图时(一次在测试中,一次在代码中),它们两个错误的可能性非常低(除非已经要求是错误的)。这可以与会计师使用的双重记账簿进行比较。见http://butunclebob.com/ArticleS.UncleBob.TheSensitivityProblem

最近在http://blog.objectmentor.com/articles/2009/01/31/quality-doesnt-matter-that-much-jeff-and-joel

的评论中讨论了同样的问题

关于你的问题,应该测试GUI测试库...如果我理解正确,你就是在制作自己的测试库,并且想知道你是否应该测试你的测试库。是。为了能够依赖库来正确地报告测试,您应该进行测试以确保库不报告任何误报或漏报。无论测试是单元测试,集成测试还是验收测试,都应该至少进行一些测试。

通常在编写代码之后编写单元测试为时已晚,因为代码往往更加耦合。单元测试强制代码更加分离,因为否则不能单独测试小单元(类或密切相关的类组)。

当代码已经编写完成后,通常只能添加集成测试和验收测试。它们将在整个系统运行时运行,因此您可以确保这些功能正常工作,但覆盖每个角落的情况和执行路径比单元测试更难。

答案 6 :(得分:2)

Kent Beck的书“测试驱动开发:通过示例”有一个测试驱动开发单元测试框架的例子,所以测试你的测试当然是可能的。

我没有使用过GUI或.NET,但您对单元测试有什么顾虑?

您是否担心在目标代码正常运行时可能会将其描述为错误?我想这是一种可能性,但如果发生这种情况,你可能会发现它。

或者您是否担心它可能会将目标代码描述为正常运行,即使它不是?如果您对此感到担心,那么mutation testing可能就是您所追求的。变异测试会更改正在测试的部分代码,以查看这些更改是否会导致任何测试失败。如果没有,那么代码没有运行,或者代码的结果没有被测试。

如果您的系统上没有变异测试软件,那么您可以通过自己破坏目标代码并查看是否导致单元测试失败来手动进行变异。

如果您正在构建一组与特定应用程序无关的单元测试产品,那么您可能应该构建一个简单的应用程序,您可以运行您的测试软件并确保它获得预期的失败和成功。

突变测试的一个问题是它不能确保测试涵盖程序可能遇到的所有潜在场景。相反,它只能确保目标代码预期的场景都经过测试。

答案 7 :(得分:2)

我们通常使用这些经验法则:

1)所有产品代码都有单元测试(安排与产品代码类和功能紧密对应)和单独的功能测试(由用户可见的功能排列)

2)不要为第三方代码(如.NET控件或第三方库)编写测试。例外情况是,如果您知道它们包含您正在解决的错误。对此进行回归测试(当第三方错误消失时失败)会在第3方库的升级修复错误时提醒您,这意味着您可以删除解决方法。

3)单元测试和功能测试本身并未直接测试 - APART使用TDD程序在产品代码之前编写测试,然后运行测试以观察它失败。如果你不这样做,那么你会感到非常惊讶意外地编写总是通过的测试是多么容易。理想情况下,您可以一步一步地实现产品代码,并在每次更改后运行测试,以便查看测试中的每个断言都失败,然后实现并开始传递。然后你会看到下一个断言失败。通过这种方式,您的测试可以进行测试,但只有在编写产品代码时才会进行测试。

4)如果我们从我们的单元或功能测试中分解代码 - 创建一个在许多测试中使用的测试库,那么我们会对所有这些进行单元测试。

这对我们很有帮助。我们似乎始终坚持这些规则100%,我们对我们的安排非常满意。

答案 8 :(得分:2)

答案

是的,您的GUI测试库应该进行测试。

例如,如果您的库提供检查方法以针对二维数组验证网格的内容,则您希望确保它按预期工作。

否则,测试网格必须接收特定数据的业务流程的更复杂的测试用例可能不可靠。如果检查方法中的错误产生错误否定,您将很快发现问题。但是,如果它产生误报,你就会遇到严重的问题。

测试 CheckGrid 方法:

  • 使用已知值填充网格
  • 使用填充的值
  • 调用 CheckGrid 方法
  • 如果这种情况通过, CheckGrid 的至少一个方面可以正常工作。
  • 对于第二种情况,您希望 CheckGrid 方法报告测试失败。
  • 您如何表明期望的细节将取决于您的xUnit框架(稍后参见示例)。但基本上,如果 CheckGrid 未报告测试失败,则测试用例本身必须失败。
  • 最后,您可能需要针对特殊条件的更多测试用例,例如:空网格,网格大小不匹配的数组大小。

您应该能够为大多数框架修改以下dunit示例,以便测试 CheckGrid 是否正确检测到错误:

begin
  //Populate TheGrid
  try
    CheckGrid(<incorrect values>, TheGrid);
    LFlagTestFailure := False;
  except
    on E: ETestFailure do
      LFlagTestFailure := True;
  end;
  Check(LFlagTestFailure, 'CheckGrid method did not detect errors in grid content');
end;

让我重申一下:你的GUI测试库应该进行测试;而诀窍是 - 你如何有效地做到这一点?

TDD流程建议您首先弄明白 实施之前测试新功能 。原因是,如果你不这样做,你经常会发现自己正在试图验证它是如何工作的。将测试用例改进现有的实现是非常困难的。

旁注

你说的一件事让我感到困扰......你说需要“70%(你的时间)维持(你的测试)”

这对我来说听起来有点不对,因为理想情况下你的测试应该很简单,如果你的接口或规则发生变化,它们本身只需要改变。

我可能误解了你,但我觉得你不会写“生产”代码。否则,您应该更好地控制测试代码和生产代码之间的切换周期,以减少您的问题。

一些建议:

  • 注意非确定性值。例如,日期和人工密钥可能会对某些测试造成严重破坏。您需要一个明确的策略来解决这个问题。 (另一个答案是单独的。)
  • 您需要与“生产开发人员”密切合作,以确保您正在测试的界面的各个方面能够稳定下来。即他们需要了解您的测试如何识别GUI组件并与GUI组件交互,因此他们不会随意更改“不影响他们”的更改。
  • 在上一点上,如果自动化测试在进行更改时运行,将会有所帮助。
  • 你也应该警惕过多的测试,简单地归结为任意排列。例如,如果每个客户都有A,B,C或D类;然后4个“新客户”测试(每个类别1个)为您提供3个额外的测试,这些测试并不比第一个测试更能说明,并且“难以维护”。

答案 9 :(得分:1)

就个人而言,我没有对我的自动化库进行单元测试,我针对基线的修改版本运行它们以确保所有检查点都能正常工作。这里的原理是我的自动化主要用于回归测试,例如当前运行的结果与期望结果相同(通常这相当于上次运行的结果)。通过针对适当修改的预期结果集运行测试,所有测试都会失败。如果他们不是,那么您的测试套件中就会出现错误。这是从变异测试中借鉴的概念,我发现它非常适合检查GUI自动化套件。

答案 10 :(得分:1)

从您的问题中,我可以理解您正在构建用于执行自动化测试的关键字驱动框架。在这种情况下,始终建议对常用和GUI实用程序功能进行一些白盒测试。既然您对图书馆中每个GUI测试功能的单元测试感兴趣,请继续。测试总是很好。这不是浪费时间,我会将其视为您框架的“增值”。

您还提到过处理测试代码,如果您的意思是测试方法,请将执行类似工作的不同功能/模块分组,例如:GUI元素验证(在线状态),GUI元素输入,GUI元素读取。为不同的元素类型分组,并为每个组执行类型单元测试方法。您可以更轻松地跟踪测试。干杯!

答案 11 :(得分:0)

我建议测试测试是个好主意,必须要做的事情。只需确保您正在构建的用于测试应用的内容并不比应用程序本身更复杂。正如之前所说的,即使在构建自动化功能测试时,TDD也是一种很好的方法(我个人不会这样做,但无论如何这都是一种很好的方法)。对测试代码进行单元测试也是一种很好的方法。恕我直言,如果您正在自动化GUI测试,只需继续进行任何可用的手动测试(您应该有步骤,原始方案,预期结果等),确保它们通过。然后,对于您可能创建并且尚未手动编写脚本的其他测试,请对它们进行单元测试并遵循TDD方法。 (如果你有时间可以对其他的进行单元测试)。 最后,关键字驱动,是IMO,您可以遵循的最佳方法,因为它为您提供了最灵活的方法。

答案 12 :(得分:0)

您可能想要探索变异测试框架(如果您使用Java:请查看PIT Mutation Testing)。评估单元测试质量的另一种方法是查看由SonarQube等工具提供的报告;报告包括各种coverage metrics;