【问题标题】:External Data File for Unit Tests单元测试的外部数据文件
【发布时间】:2010-11-08 03:46:33
【问题描述】:

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

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

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

我为什么要这样做

我已经阅读了使用 JUnit 在 Java 中进行的实用单元测试,这给出了一个带有外部数据文件的示例,这让我觉得这没问题。另外,这意味着我不需要为了测试不同的数据而使用非常相似的代码编写大量单元测试。

但另一方面......

如果我正在测试:

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

都在同一个测试数据文件中(因此在同一个测试中)这会在以后给我带来问题吗?我读到一个测试应该只因一个原因而失败。

我做的好吗?

其他人如何在他们的单元测试中使用测试数据?

【问题讨论】:

    标签: cocoa unit-testing xcode


    【解决方案1】:

    【讨论】:

    • 很好的链接。真的很有帮助。谢谢。
    【解决方案2】:

    虽然我认为这是一个完全合理的问题,但我认为您不应该对此过分担心。严格来说,每个测试应该只测试一件事是正确的,但这并不妨碍您使用数据文件。

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

    您所描述的是数据驱动测试(也称为参数化测试)。如果您保持测试本身简单,则向其提供不同的数据本身并没有问题。

    需要关注的是,您希望能够在几个月后/如果发生这种情况时快速找出测试失败的原因。如果您的测试输出指向测试数据文件中的特定行,您应该能够快速找出问题所在。另一方面,如果您收到的唯一消息是测试失败并且文件中的任何行都可能有问题,那么您将开始看到测试可维护性噩梦的轮廓。

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

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

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

    【讨论】:

    • 一个非常有用的答案。有趣的是,您对数据文件的容忍度比接受的答案要多。您的回答有助于为我提供更广泛的意见 - 与所有事情一样,很大程度上取决于意见和判断,但连同公认的答案,我有一些很好的起点来做出自己的明智决定。非常感谢!
    【解决方案3】:

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

    • 您的测试代码分为测试代码和测试数据文件。这使测试更难理解和维护。
    • 您希望尽可能快地进行单元测试。进行不必要地读取数据文件的测试可能会减慢您的测试速度。

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

    • 输入很大(例如,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);
    }
    

    【讨论】:

    • 天哪。这非常有帮助。这正是我所寻求的建议。我觉得在外部文件中写了这么多我的验证数据有点奇怪,但我不知道为什么。您的回答使我感到不好-这对可维护性和速度不利。作为我自己代码的起点,您的示例代码也非常有用。谢谢。太棒了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-03
    • 2019-04-18
    相关资源
    最近更新 更多