组织我们的单元测试的最佳方法是什么


18

这些年来,我们已经为主要程序建立了大量的单元测试。几千。问题在于,由于测试太多,我们没有明确的想法。这是一个问题,因为我们不知道测试的弱点(或重复的地方)。

我们的应用程序是一个报告引擎。因此,您可以有一个模板用于测试解析(我们是否读取了所有表属性),合并数据(是否在合并中保留了正确的表属性),格式化了最终页面(表格是否正确放置在页面上? )和/或输出格式(创建的DOCX文件正确)。

除此之外,我们需要测试。在表格单元格周围填充(我们使用Word,Excel和PowerPoint进行报表设计)。我们必须测试跨分页符的填充情况,对于单元格内的表,垂直合并的单元格,水平合并的单元格,垂直和水平合并的单元格(其中包含一个表,内部表中的垂直和水平合并的单元格),该表跨页中断。

那么该测试属于哪一类?表格填充,分页符,嵌套单元格,垂直合并的单元格,水平合并的单元格或其他内容?

以及我们如何记录这些类别,命名单元测试等?

更新:许多人建议使用覆盖率工具来验证我们是否具有完整覆盖率。不幸的是,这在我们的案例中用途有限,因为这些错误往往是由于特定的组合所致,因此已经对所有代码进行了测试,但没有进行组合。

例如,昨天有一个客户在其模板(Word文档)的forEach循环的末尾开始了Word书签,并在下一个forEach循环的末尾结束了它。所有这些都使用了针对其进行了单元测试的代码,但是我们没有想到将模板扩展为书签的组合从开始开始25次,然后结束10次(两个forEach循环具有不同的行数)。


1
看来您的问题确实是,我们如何知道我们已经测试了特定方案?
2011年

是! 还有任何类似场景的测试在哪里。因此,我们获得了第二大需求-阅读涵盖的内容有助于我们找到我们错过的内容。
David Thielen

Answers:


13

通常,我倾向于为单元测试镜像源代码树。因此,如果我有src / lib / fubar,我将拥有一个test / lib / fubar,其中包含fubar的单元测试。

但是,您似乎要描述的是更多的功能测试。在这种情况下,我将拥有一个多维表,其中列出了所有可能的条件。然后,那些没有测试的测试要么毫无意义,要么需要新的测试。当然,您可以将它们放在测试套件中。


我们目前镜像源代码树。但是我们有两个问题。首先,对于表格格式化,有100多种不同的测试。跟踪精确测试的内容已经成为一个问题。其次,非常不同的功能区域需要测试表-解析器,数据替换,格式设置以及创建输出文档。所以我认为您是对的,从某种意义上说,这是对给定属性的功能测试。
大卫·蒂伦

这就引出了一个问题,我们将测试表存储在哪里?我在想根源目录中的电子表格???
大卫·蒂伦

我会将其存储在测试目录中的版本控制的电子表格中。如果您需要测试很多东西,将其分解为元结构将是有益的。尝试根据正在测试的一般事物而不是什么或如何进行思考。
Sardathrion-恢复莫妮卡2011年

7

最常见的结构似乎是srcand test目录镜像。

src/module/class
test/module/class_test

但是,我看到了一种替代结构,现在我认为它会更好。

src/module/class
src/module/class_test

由于单元测试倾向于反映他们正在测试的类,因此将它们放在同一目录中可以更轻松地访问文件,因此您可以并排工作。


2
前一种方法的缺点是,每次决定更改项目的文件结构时,都必须对测试结构进行相同的操作。如果测试在代码所在的位置,则不存在此问题。
victor175 '18

5

在.NET中,我倾向于在“ Tests.Unit”或“ Tests.Integration”主命名空间下镜像或至少近似地反映测试项目中源代码的命名空间结构。所有单元测试都在一个项目中,源代码的基本结构被复制为项目中的文件夹。集成测试相同。因此,一个项目的简单解决方案可能如下所示:

Solution
   MyProduct.Project1 (Project)
      Folder1 (Folder)
         ClassAA (Class def)
         ...
      Folder2
         ClassAB
         ...
      ClassAC
      ...
   MyProduct.Project2
      Folder1
         ClassBA
         ...
      ClassBB
      ...
   ...
   MyProduct.Tests.Unit
      Project1
         Folder1
            ClassAATests
            ClassAATests2 (possibly a different fixture setup)
         Folder2
            ClassABTests
         ClassACTests
      Project2
         Folder1
            ClassBATests
         ClassBBTests
      ...
   MyProduct.Tests.Integration
      Project1 (a folder named similarly to the project)
         Folder1 (replicate the folders/namespaces for that project beneath)
            ClassAATests
         Folder2
            ClassABTests
         ClassACTests
      Project2
         Folder1
            ClassBATests
         ClassBBTests

对于使用单元测试框架进行编码的任何AAT或AEET,这都会有所变化。通常,这些测试反映了一组步骤,这些步骤将测试新用例或故事的功能。我通常在这样的MyProduct.Tests.Acceptance项目中构造这些测试,并针对每个故事进行测试,并可能按正在开发的故事所属的里程碑或“史诗”故事进行分组。但是,这些实际上只是超级集成测试,因此,如果您更喜欢以面向对象而不是面向故事的方式构建测试,则您甚至不需要一个MyProduct.Tests.Acceptance或类似的项目。只需将它们放入要MyProduct.Tests.Integration测试的最高级别对象的范围内即可。


3

没有理由将单元测试仅放在一个类别中。所有主要的单元测试工具包都支持创建测试套件,该套件捆绑了特定类别的测试。当特定的代码区域已更改时,开发人员应首先运行该套件,并经常查看有什么问题。当测试涉及填充中断嵌套时,请务必将其放入所有三个套件中。

就是说,单元测试的重点是一直运行它们,即它们应该足够小并且足够快,以便在提交任何代码之前可以运行它们。换句话说,测试是什么类别并不重要,应该在提交之前运行它。套件实际上只是您使用的拐杖,如果由于某种原因您不能编写出其应有的速度那么快的测试。

至于覆盖率,有非常好的覆盖率工具可以告诉您通过运行测试实际行使了多少百分比的行-这显然是您仍然缺少哪种测试的指针。

至于命名,在单元测试名称上花费精力没有特别的价值。您想从测试中听到的是“通过5235个测试中的5235个”。当测试失败时,您读取的不是其名称,而是消息,例如assert()实现成功标准的字符串。该消息应足够翔实,以至于您无需阅读测试内容即可了解出了什么问题。与之相比,这个名字并不重要。


对您说的所有内容达成100%的同意(我们的构建机器会在签入时运行所有测试)。我们的最大问题是跟踪我们正在测试的内容。而且代码覆盖范围并没有太多帮助(请参阅上面的更新)。
大卫·蒂伦

1

知道您是否在测试方面不强的一种方法是可追溯性。通常用于测试,采取覆盖的形式。

目的是测量测试将执行代码的哪些部分,以便您可以查看测试未涵盖的代码。由您(和覆盖率工具)决定什么是“代码的一部分”。最少的是分支机构覆盖率。

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.