单元测试的外部数据文件

时间:2009-07-04 22:10:32

标签: cocoa unit-testing xcode

我是单元测试的新手,我正在接受一些最佳实践建议。我正在使用Xcode在Cocoa中编码。

我有一个方法可以验证用户输入的网址。我希望它只接受http://协议,只接受有效字符的URL。

对此进行一次测试并使用测试数据文件是否可以接受?数据文件提供示例有效/无效URL以及URL是否应该验证。我也用它来检查错误消息的描述和域。

为什么我这样做

我已经用JUnit阅读了Java中的语用单元测试,这给出了一个外部数据文件的例子,这让我觉得这没关系。另外,这意味着我不需要用非常相似的代码编写大量单元测试来测试不同的数据。

但另一方面......

如果我正在测试:

  • 无效字符
  • 无效的协议
  • 有效网址

所有在相同的测试数据文件中(因此在同一测试中)这会在以后引起我的问​​题吗?我读到一个测试应该只是因为一个原因而失败。

我正在做什么?

其他人如何在单元测试中使用测试数据(如果有的话)?

3 个答案:

答案 0 :(得分:5)

通常,仅在必要时使用测试数据文件。使用测试数据文件有许多缺点:

  • 测试代码在测试代码和测试数据文件之间分配。这使得测试更难以理解和维护。
  • 您希望尽快保持您的单元测试。测试不必要地读取数据文件可能会减慢测试速度。

在某些情况下我会使用数据文件:

  • 输入很大(例如,XML文档)。虽然您可以使用字符串连接来创建大型输入,但它可能会使测试代码难以阅读。
  • 测试实际上是测试读取文件的代码。即使在这种情况下,您可能希望测试在临时目录中编写示例文件,以便测试的所有代码都在一个位置。

我建议不要在文件中编码有效和无效的URL,而是建议在代码中编写测试。我建议为无效字符创建测试,测试无效协议,测试无效域,以及测试有效URL。如果您认为没有足够的覆盖范围,则可以创建一个小型集成测试来测试多个有效和无效的URL。这是Java和JUnit中的一个例子:

public void testManyValidUrls() {
  UrlValidator validator = new UrlValidator();
  assertValidUrl(validator, "http://foo.com");
  assertValidUrl(validator, "http://foo.com/home");
  // more asserts here
}

private static void assertValidUrl(UrlValidator validator, String url) {
  assertTrue(url + " should be considered valid", validator.isValid(url);
}

答案 1 :(得分:1)

虽然我认为这是一个非常合理的问题,但我认为你不应该过分关注这个问题。严格地说,你是正确的,每个测试应该只测试一件事,但这并不排除你使用数据文件。

如果您的被测系统(SUT)是一个简单的URL解析器/验证器,我认为它需要一个URL作为参数。因此,您可以将多少同时无效的数据输入其中,这是一个限制。即使您输入包含无效字符和无效协议的URL,也只会导致单个结果(该URL无效)。

您所描述的是数据驱动测试(也称为参数化测试)。如果你保持测试本身很简单,用不同的数据喂它就不会有问题。

做什么需要关心的是,你希望能够快速找到测试失败的原因/在几个月之后发生。如果您的测试输出指向测试数据文件中的特定行,您应该能够快速找出出错的地方。另一方面,如果您获得的唯一消息是测试失败并且文件中的任何行可能出错,您将开始看到测试可维护性噩梦的轮廓。

就个人而言,我略微倾向于让测试数据尽可能与测试密切相关。那是因为我认为测试作为可执行规范的概念非常重要。当测试数据在每个测试中被硬编码时,它可以非常清楚地指定输入和预期输出之间的关系。从测试本身中删除的数据越多,读取此“规范”就越困难。

这意味着我倾向于在每个测试中定义输入数据的值。如果我必须编写许多非常相似的测试,其中唯一的变化是输入和/或预期输出,我编写参数化测试,但仍然从硬编码测试中调用参数化测试(每个只是一行代码)。我认为我从未使用过外部数据文件。

但是,这些天,我甚至知道我的输入是什么,因为我使用Constrained Non-Determinism。相反,我使用等价类和Derived Values

答案 2 :(得分:1)