我主要是一个C++程序员,到目前为止,我还没有真正为我的所有代码编写测试。我认为这是一个糟糕的想法(Tm),在添加了一些新特性之后,这些特性巧妙地打破了旧特性,或者,根据您的意愿,引入了它们自己的一些新的“特性”。
但是,单元测试似乎是一种极其脆弱的机制。您可以在“完美”条件下测试代码,但当代码中断时,您将无法查看代码的执行情况。例如,A是一个爬虫,假设它爬行了几个特定的站点,对于数据X,您是否只是保存示例页面,对这些页面进行测试,并希望这些站点永远不会改变?作为回归测试,这会很好,但是,您会编写什么样的测试来不断地检查这些站点,并让您知道当应用程序没有完成它的工作,因为站点改变了一些东西,这会导致您的应用程序崩溃?您不希望您的测试套件监视代码的意图吗?
上面的例子有点做作,有些东西我还没有碰到(万一你还没猜到)。不过,让我挑点我有的东西。面对降级的网络堆栈,如何测试应用程序将完成其工作?也就是说,假设您由于某种原因有一定数量的数据包丢失,并且您有一个函数DoSomethingOverTheNetwork(),它应该在堆栈没有按预期执行时优雅地退化;但是它是吗?开发人员亲自对其进行测试,目的是在第一次编写该网关时设置一个丢弃数据包以模拟不良网络的网关。几个月后,有人签入了一些代码,这些代码巧妙地修改了某些内容,因此无法及时检测到退化,或者,应用程序甚至无法识别退化,这是从未捕捉到的,因为您不能使用单元测试来运行这样的真实世界测试,对吗?
此外,文件腐败又如何?假设您将服务器列表存储在文件中,校验和看起来还可以,但数据并不是真的。要想让代码来处理这个问题,就需要编写一些您认为可以这样做的代码。如何测试它在应用程序的生命周期中确实做到了这一点?你能?
因此,脆性。单元测试似乎只在完美的条件下测试代码(这是通过模拟对象之类的方式进行的),而不是它们在野外所面临的问题。不要误解我的意思,我认为单元测试很棒,但是一个只由它们组成的测试套件似乎是一种聪明的方法,可以在代码中引入微妙的bug,同时对它的可靠性过于自信。
我如何处理上述情况?如果单元测试不是答案,又是什么呢?
编辑:我看到很多回答说“只是嘲笑它”。好吧,您不能“只是嘲笑它”,原因如下:以我的退化网络堆栈为例,让我们假设您的函数有一个定义良好的NetworkInterface,我们将对其进行模拟。应用程序通过TCP和UDP发送数据包。现在,让我们假设,嘿,让我们用一个模拟对象来模拟界面上10%的损失,看看会发生什么。您的TCP连接增加了它们的重试尝试,同时也增加了它们的备份,这些都是很好的实践。您决定将UDP数据包的X%更改为实际建立TCP连接、有损接口,我们希望能够保证某些数据包的传递,而其他数据包不应丢失太多。效果很好。同时,在现实世界里..。当增加TCP连接(或TCP上的数据)的数量时,在有足够损耗的连接上,最终会增加UDP数据包丢失,因为TCP连接最终会越来越多地重新发送它们的数据和/或减少它们的窗口,导致10%的数据包丢失实际上更接近90%的UDP数据包丢失。哇哦。
没什么大不了的,让我们把它分成UDPInterface和TCPInterface。等一下..。这些是相互依赖的,测试10%的UDP损失和10%的TCP丢失与上述没有什么不同。
因此,现在的问题是,您不仅要对代码进行单元测试,还要在操作系统的TCP堆栈的工作方式中引入您的假设。这是个坏主意。一个比避免这场惨败更糟糕的主意。
在某种程度上,您将不得不创建一个Mock OS,它的行为与您真正的操作系统完全一样,只是它是可测试的。这似乎不是个好办法。
这是我们经历过的事情,我相信其他人也能增加他们的经验。
我希望有人会告诉我我错了,并指出原因!
谢谢!
发布于 2010-12-29 15:49:34
阅读任何一本关于单元测试的好书--你会发现通常会编写一些测试,这些测试实际上涵盖了输入不理想或明显错误的边缘情况。
在具有异常处理的语言中,最常见的方法是“应该抛出”规范,其中预期某个测试会导致抛出特定的异常类型。如果不抛出异常,则测试将失败。
更新
在您的更新中,您描述了复杂的时间敏感交互。单元测试在那里根本没有帮助。不需要引入网络:只需要尝试编写一个简单的线程安全队列类,也许是在带有一些新的并发原语的平台上编写。在一个8核心系统上测试..。起作用了吗?你不可能通过测试就知道这一点。有太多不同的方式,时间可能会导致操作之间的核心重叠。取决于运气,可能需要数周的持续执行,才会出现一些真正不太可能发生的巧合。正确处理这些事情的唯一方法是通过仔细的分析(静态检查工具可以帮助)。很可能大多数并发软件中都有一些很少出现的错误,包括所有的操作系统。
回到实际可以测试的情况,我发现集成测试通常与单元测试一样有用。这可以像自动安装产品、向其添加配置(比如用户可能创建的配置)、然后从外部“戳”它一样复杂,例如自动化UI。这发现了与单元测试不同的另一类问题。
发布于 2010-12-29 16:00:38
首先讨论单元测试,然后讨论整个应用程序;似乎您对单元测试是什么感到有点困惑。根据定义,单元测试是在软件的每个“单元”被测试时,在最细粒度级别上进行的测试。在常用的情况下,“单元”是一个单独的函数,而不是整个应用程序。当代的程序设计风格功能很短,每一种功能都有一个很好的定义,因此很容易进行单元测试。
发布于 2010-12-29 16:17:24
您会写什么样的测试来不断地检查这些站点的实况?
UnitTests以您编写的代码的小部分为目标。UnitTests不确认世界上一切都很好。相反,您应该为那些不完美的场景定义应用程序行为。然后,您可以在这些不完美的场景中对应用程序进行UnitTest。
例如,爬虫
爬虫是你可能编写的大量代码。它有一些不同的部分,其中一部分可能会获取一个网页。另一部分可能分析html。即使是这些部分也可能太大,无法编写单元测试。
面对降级的网络堆栈,如何测试应用程序将完成其工作?开发人员亲自对其进行测试,目的是在第一次编写该网关时设置一个丢弃数据包以模拟不良网络的网关。
如果测试使用网络,那么它不是UnitTest。
UnitTest (必须针对您的代码)不能调用网络。网络不是你写的。UnitTest应该包含一个模拟网络,模拟(但每次都是一致的)丢包。
单元测试似乎只在完美的条件下测试代码。
UnitTests在定义的条件下测试代码。如果你只能定义完美的条件,你的陈述是正确的。如果你能够定义不完美的条件,你的陈述是错误的。
https://stackoverflow.com/questions/4555486
复制相似问题