4

我通常会尝试对任何可以轻松定义正确行为的代码使用单元测试,这些代码给出了一些相当小的、定义良好的输入集。这对于捕获错误非常有效,我一直在我的个人通用函数库中这样做。

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

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

4

6 回答 6

3

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

  1. 您的代码正确地实现了给定的数据挖掘算法(这个东西你应该单元测试)
  2. 您实现的数据挖掘算法是“正确的”——解决了业务问题。这是一个非常开放的问题,它可能既取决于算法的某些参数,也取决于实际数据(不同的算法适用于不同类型的数据)。
于 2009-03-18T18:05:50.843 回答
3

当面对这样的情况时,我倾向于构建一个或多个存根数据集,以反映现实生活中数据的适当潜在复杂性。我经常与客户一起这样做,以确保我抓住了复杂性的本质。

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

于 2009-03-18T18:07:15.130 回答
1

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

另一种是将程序的每个组件分解为可测试的部分。如果A调用B调用C调用D,并且你知道A、B、C、D都给出正确答案,那么你测试A->B、B->C和C->D,那么你可以合理地确定 A->D 给出了正确的响应。

此外,如果有其他程序可以做您想做的事情,请尝试获取他们的数据集。或者你可以使用测试数据的开源项目,看看你的应用程序是否给出了类似的结果。

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

而且,经过验证的真实情况,手动浏览您自己的代码,看看代码是否按照您的意图执行。

于 2009-03-18T18:06:25.693 回答
0

确实,这里的挑战是:因为您的应用程序旨在以一种智能的方式执行一项模糊的、非确定性的任务,您希望实现的目标是应用程序在发现这些模式方面变得比人类更好。这很棒,很强大,很酷……但是如果你成功了,那么任何人都很难说,“在这种情况下,答案应该是 X。”

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

如果你真的成功实现了最初的目标,最终用户有时可能会说,“Zowie,你是对的。这是一个更好的答案。你找到了一个可以让我们赚钱的模式!(或者为我们省钱,或者任何)。”

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

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

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

此外,如果你能做到,如果系统能够在它检测到的模式背后“描述其推理”,那就太好了。这将让业务用户仔细考虑应用程序是否正确的问题。

于 2009-03-20T03:23:18.977 回答
0

这很棘手。这听起来类似于围绕我们的文本搜索引擎编写测试。如果你继续努力,你会想出一些办法:

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

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

于 2009-03-18T18:05:48.910 回答