运输测试代码。你为什么不呢?


17

我想将测试代码与产品一起提供。具体来说,提供一个选项,以便拥有我们程序副本的任何人都可以单击“自检”按钮或在命令行上通过--self-test并运行完整的单元| 集成测试。

我主要是想这样做,以帮助调试在现场发现的问题,因此,当最终用户收到错误报告时,“并且这三项测试在我的计算机上都失败了”,这有可能会为它提供支持。我希望手动测试仪能够运行该单元| 集成测试。

但是,团队的测试认为测试代码不是生产代码,因此不应发货。因为大多数开源项目都附带了一个测试套件,所以我并没有真正理解这个论点。在封闭的软件中,这确实不寻常。

我想为论证的任何方面提供证据或轶事。我已经最好地猜测了哪个堆栈交换站点最合适,但是如果这不合适,请告诉我。


8
为什么封闭源程序(或未经修改的开放源程序)中的单元测试会失败?如果您的产品需要大量的设置,并且设置问题通常是错误的根源,则可能需要交付某种“验证我的配置”应用程序,该程序执行诸如验证数据库连接,验证与任何其他外部服务的连接之类的操作您的代码取决于。等等。但是,因为您已经验证了代码可以工作,所以单元测试永远不会失败。
贾斯汀·凯夫


15
为什么单元测试在现场会失败?让我烦恼的是:腐败的程序。狡猾的硬件。我们在当地看不到的比赛条件。链接到另一个动态库。与防病毒或操作系统冲突。由于更新不完整,与令人惊讶的相关软件版本一起使用。与其他进程的交互行为不符合预期。现场出现错误的原因很多,对于单元的给定定义,单元测试可能会击中很多错误
Jon Chesterfield

7
@JonChesterfield:在程序中创建自检功能可能是一件好事。如果该自测功能可以部分重用单元测试中的代码,那为什么不呢?但是,应从“这是生产代码”的角度开发此类功能以及可重复使用的零件。
布朗

2
@JonChesterfield我很难想象在大多数这些原因上导致单元测试失败。不过,集成测试是另一回事-如果不需要太多额外的东西就可以完成集成测试,我可以看到优点。
罗伦·佩希特尔

Answers:


19

有时,测试代码包含来自公司内部和外部的第三方代码段。这是由于用户提交错误而发生的。您的测试(例如回归测试)然后结合它们提供的代码进行复制。通常,此类代码段的许可是否可以重现错误尚不清楚。因此,您应该注意知识产权问题。您不希望发布会意外泄露公司其他部门或外部合作伙伴的某些商业秘密或知识产权的测试代码。

另一方面,测试代码很少符合生产代码标准。编码标准未得到执行等。这是不幸的,但是很平常,如果在开发这些测试时他们没有达到目标,就不一定会对测试团队产生不良影响。

另一方面,许多测试简直令人尴尬地糟糕,甚至根本没有测试某些人认为正在测试的东西。那是不同的问题...

归根结底,由于所有这些因素,您可能希望将测试分类为可以作为开源交付的测试,以及那些根本不能交付的测试。(您可能希望编写一些自定义测试,并牢记这些测试,然后将其他测试慢慢迁移到该测试集中。)


第三方问题是一个很好的观点。将测试代码分为“外部可见”和“可能是机密的”易于出错并且产生大量开销。谢谢,这本身就是一个大难题。
乔恩·切斯特菲尔德

是的,事后很难做。我想您会付出更多的努力来开发运输测试。
Erik Eidt

@ErikEidt:我可以自由地提出删除“作为开源”的建议,因为这可能不是OP的初衷-我认为他想将测试作为封闭源发布。
布朗

@DocBrown,我明白你的意思。OP确实在帖子中提到了“开源”,这可能是一个解释问题。无论如何,您的编辑都能很好地概括这一点。
Erik Eidt

18

出货测试?是。运输单元测试?没有。

正如您在评论中所说,在客户端计算机上运行产品时,您可能会遇到的问题将包括诸如与错误的dll链接之类的问题,通常这不是单元测试所能解决的(毫无疑问,这将使dll被嘲笑)测试代码)。

现在,提供了一个集成测试套件,该套件会调用UI,该UI会调用dll的逻辑……这会更好地工作。集成测试可以显示失败的安装的其他方面,而单元测试不会显示这些方面。(例如,我当前的产品需要安装k-lite编解码器,由于许可原因,我们不允许将其捆绑在一起。单元测试可能表明我们的代码可以正常工作,但仍然无法满足客户的需求。类似地,我们对编解码器的配置可能无法正常工作,单元测试也不会显示出来)。

因此-改为提供一些集成测试,这正是您要安装的集成产品所需的。


2

我可以在您覆盖硬件的每一英寸的领域中深刻理解这种担忧,例如使用多线程的下一代AAA游戏引擎,该引擎使用每个CPU内核,SIMD内在函数,GPU,GPGPU等,同时提供跨平台产品。

在这些情况下,最糟糕的噩梦通常是在测试的前5,000个不同的机器/平台上测试(单元和集成)通过的情况,但由于驱动器错误(用于模糊的GPU模型)而导致测试失败(第5001个),关于这一点,我感到不寒而栗-您可能无法预先测试或预见到这些。

尤其是如果您编写GPU着色器,您最终可能会玩反向抽奖,其中所编写的一半代码将调用未定义的行为,因为涉及的所有GPU型号/驱动程序都几乎没有实施可移植的标准保证。尽管最近越来越像玩扫雷车了,这应该给人们一些想法:http : //theorangeduck.com/page/writing-portable-opengl。在90年代末和2000年代初尝试这种方法确实很可怕,而且扫雷一直到此为止。

对于此类情况,您通常需要由10,000多名测试人员组成的团队使用,它们具有非常广泛的硬件和操作系统,才能真正巩固产品并在稳定发布之前对此充满信心。并非所有的公司都不能有这样一个广泛的试验基地,并且不是所有有纪律做是正确的(所有广泛注意的问题应该是固定的在一些内部预阿尔法/ alpha阶段,否则,有这么多的测试人员大量的冗余报告可能会使开发人员陷入补丁祈祷的恐慌中。

在这种情况下,我的建议是其他人的建议,重点是一组分布式集成测试。您可以将其与安装程序捆绑在一起,要求用户通过基本的诊断检查,并要格外注意,以提供有关安装失败的详细信息,以便他们可以将这些信息传递给开发人员。

另一件事(如果可以说服老板)是拥有广泛的硬件来进行连续集成。硬件/ OS组合的种类越多,越好。您甚至需要各种各样的垃圾硬件来模拟CI服务器的最低硬件需求:您永远不会知道。

但我建议再做一件事:

记录中

如果您正在处理如上所述的情况,那么通常您可能无法测试这些问题最多的东西(那些最坏的陷阱在最坏的时间出现,甚至在最坏的时间也不会出现)。最详尽的测试套件,因为这是一个非常特定的硬件/ OS组合的问题)。

但是,大多数这类问题,例如模糊的硬件不兼容或完全的驱动程序故障或与错误的dylib链接(我从来没有真正面对过这种担心),都不会使您超出启动软件的范围。简而言之,它通常会崩溃并很快燃烧。

为了理智起见,我建议一定要接受这种不可避免的情况。您无法对这些事情做任何事情,而无法全面测试。不要试图防止飓风(不可能),而要登上那些窗户。

通常,在这里,我们能做的最好的事情就是尽快找出问题所在,并尽可能详细地进行(以缩小可疑范围),并在报告后尽快解决问题。

在这种情况下,日志记录可以节省时间。对于这些类型的字段,您可以创建这些垃圾邮件技术日志,没人会读过。经常相关的只是用户由于驱动程序故障而导致崩溃之前日志中记录的最后一行,例如,您可以编写一个外部进程或挂钩来监视崩溃,然后显示用户可以复制的日志的最后一行并粘贴到您那里,例如,除了故障转储之外。

由于这通常需要详细的信息,并且代码中许多最容易受这些硬件/平台/驱动程序问题影响的区域对于性能至关重要,因此存在一个尴尬的问题,即日志记录的发生频率如此之高,以至于它实际上会变慢下载软件。

在这种情况下,一个有用的技巧是依靠这样的假设,即一次执行一次的东西将在第二次,第三次等成功执行。这不是最合理的假设,但它通常是“足够好”的(并且无限总比没有好) 。这样,您可以使用一点外部状态来跟踪何时已记录某些内容,并跳过随后的尝试来记录那些在循环中反复调用代码的真正粒度情况。

无论如何,我希望这会有所帮助。过去我曾遇到过这种诱惑,由于我和我的团队过去的一些经验(有时只是看到其他团队成员真正地处理了这些问题),因此围绕GPU编码(GPGPU和着色器)有些偏执后期和发行后的问题使我感到毛骨悚然,例如特定Radeon模型上的ATI故障会在渲染抗锯齿线条时崩溃,后来报告并标记为已知问题,仅提供解决方法。

日志记录是将问题保存在那的东西,让我们经常在第10,001个晦涩的原型机上使用我们从未听说过的板载GPU来查看问题,最后一行代码立即使我们能够准确地找出失败的原因,直至2或3行代码可疑,例如,如果它位于复杂的着色器中,则我们属于SOL,因为我们无法在GPU着色器中进行日志记录,但我们至少可以使用日志记录立即查看哪个着色器出现问题开始调查。


2
记住日志代码很聪明。我们目前不生成日志-主要是出于性能方面的考虑-因此调试涉及核心转储。将诊断测试与安装程序一起嵌入也是一个好主意。感谢您的详细答复。
乔恩·切斯特菲尔德
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.