正确性定义不正确时的测试?

时间:2009-03-18 17:57:21

标签: unit-testing language-agnostic automated-tests data-mining

我通常会尝试对任何代码进行单元测试,这些代码很容易定义正确的行为,给定一些相当小的,定义明确的输入。这对于捕获bug很有效,而且我一直在我的通用函数库中做到这一点。

但是,我编写的很多代码都是数据挖掘代码,它基本上可以在大型数据集中查找重要的模式。在这种情况下,正确的行为通常没有明确定义,并且取决于许多不同的输入,这些输入对于人类来说不容易预测(即数学不能合理地手工完成,这就是为什么我使用的计算机首先解决问题)。这些输入可能非常复杂,以至于提出合理的测试用例几乎是不可能的。识别值得测试的边缘情况非常困难。有时算法甚至不具有确定性。

通常,我尽我所能通过使用断言进行健全性检查并创建一个具有已知模式的小型玩具测试用例,并非正式地查看答案是否至少“看起来合理”,而不一定是客观正确的。有没有更好的方法来测试这类案件?

6 个答案:

答案 0 :(得分:3)

我认为你只需要根据一小组数据编写单元测试,以确保你的代码完全符合你的要求。如果这给你一个合理的数据挖掘算法是一个单独的问题,我认为不可能通过单元测试来解决它。您的代码有两个“级别”的正确性:

  1. 您的代码正确实现了给定的数据挖掘算法(这应该是单元测试)
  2. 您实施的数据挖掘算法是“正确的” - 解决了业务问题。这是一个非常开放的问题,它可能取决于算法的某些参数以及实际数据(不同的算法适用于不同类型的数据)。

答案 1 :(得分:3)

当遇到这样的情况时,我倾向于构建一个或多个 stub 数据集,这些数据集反映了现实生活数据的正确底层复杂性。我经常与客户一起做这件事,以确保我抓住复杂性的本质。

然后我可以将它们编成一个或多个数据集,这些数据集可以用作进行非常具体的单元测试的基础(有时它们更像是对存根数据的集成测试,但我不认为这是一个重要的区别) 。因此,虽然您的算法可能对“通用”数据集具有“模糊”结果,但这些算法几乎总是对特定数据集具有单一正确答案。

答案 2 :(得分:1)

嗯,有几个答案。 首先,正如您所提到的,进行一个小案例研究,并手工完成数学计算。既然你编写了算法,就知道它应该做什么,所以你可以在有限的情况下做到这一点。

另一个是将程序的每个组件分解为可测试的部分。 如果A呼叫B呼叫C呼叫D,并且您知道A,B,C,D都给出正确的答案,那么您测试A-> B,B-> C和C-> D,然后你可以合理地确定A-> D正在给出正确的答案。

此外,如果有其他程序可以执行您要执行的操作,请尝试获取其数据集。或者您可以使用测试数据的开源项目,并查看您的应用程序是否提供类似的结果。

测试数据挖掘代码的另一种方法是获取测试集,然后引入您正在寻找的类型的模式,然后再次测试,看它是否将新模式与旧模式分开。

并且,经验丰富,手动浏览自己的代码,看看代码是否正在执行您的意思。

答案 3 :(得分:0)

真的,这里面临的挑战是:因为你的应用程序是以一种聪明的方式做一个模糊的,非确定性的任务,你希望实现的目标是应用程序在寻找时变得比人类更好这些模式。这是伟大的,强大的,很酷的...但如果你把它拉下来,那么任何人都很难说,“在这种情况下,答案应该是X.”

事实上,理想情况下,计算机会说,“不是真的。我明白你为什么这么想,但是考虑这些4.2 TB的信息。你有没看过它们?基于这些,我认为答案应该是是Z。“

如果你真的成功实现了原来的目标,最终用户有时可能会说,“Zowie,你是对的。这是一个更好的答案。你发现了一种能让我们赚钱的模式!(或者拯救我们钱,或其他什么)。“

如果这样的事情永远不会发生,那你为什么要求计算机首先检测这些模式呢?

所以,我能想到的最好的事情就是让现实生活帮助你建立一个测试场景列表。如果过去发现的模式确实有价值,那么进行“单元测试”,看看你的系统在给出类似数据时是否发现了它。我在引号中说“单元测试”,因为它可能更像是集成测试,但您仍然可以选择使用NUnit或VS.Net或RSpec或您正在使用的任何单元测试工具。

对于其中一些测试,您可能会以某种方式尝试“模拟”4.2 TB的数据(您不会真正模拟数据,但在更高级别,您会模拟从该数据中得出的一些结论) 。对于其他人,也许您有一个“测试数据库”,其中包含一些数据,您可以从中检测出一组模式。

另外,如果你能做到这一点,那么如果系统可以在它检测到的模式背后“描述其推理”,那就太棒了。这将让业务用户审议应用程序是否正确的问题。

答案 4 :(得分:0)

这很棘手。这听起来类似于在我们的文本搜索引擎周围编写测试。如果你继续挣扎,你会想出一些事情:

  • 从一个小的,简化但具有相当代表性的数据样本开始,并测试执行此操作的基本行为
  • 有时候最好弄清楚它的重要性,而不是断言输出完全是答案。例如,对于我们的搜索引擎,我并不关心文档列出的确切顺序,只要三个关键文件在结果的第一页上。
  • 当你做一个小的,渐进的改变时,弄清楚它的本质是什么,并为此编写一个测试。尽管整体计算需要很多输入,但代码库的个别更改应该是可以隔离的。例如,我们发现某些文件没有浮出水面,因为某些关键词中存在连字符。我们创建了一些测试,用于测试这是否符合我们的预期。
  • 查看像Fitness这样的工具,它允许您在一段代码中抛出大量数据集并断言结果。与传统的单元测试相比,这可能更容易理解。
  • 我回到产品负责人那里说:“我无法理解这是如何运作的。我们怎么知道它是否正确?”也许他/她可以阐明模糊定义问题的本质。这对我来说已经非常好了 很多次,而且由于无法解释,我已经让人们谈论了功能。
  • 要有创意!

答案 5 :(得分:-2)

最终,你必须决定你的程序应该做什么,然后测试它。