代码之家  ›  专栏  ›  技术社区  ›  alexn

单元测试筛网刮刀

  •  9
  • alexn  · 技术社区  · 15 年前

    我正在写一个HTML屏幕刮刀。为此创建单元测试的最佳方法是什么?

    有一个静态HTML文件并在每次测试时从磁盘上读取它是“可以”的吗?

    你有什么建议吗?

    11 回复  |  直到 9 年前
        1
  •  3
  •   Arjan Einbu    15 年前

    为了保证测试可以反复运行,您应该有一个静态页面来测试。(即从磁盘正常)

    如果您编写的测试触及了Web上的实时页面,那么这可能不是单元测试,而是集成测试。你也可以买这些。

        2
  •  3
  •   Peter Lillevold Rene    15 年前

    文件是可以的,但:你的屏幕刮刀处理文本。您应该有不同的单元测试,“刮擦”每个单元测试中硬编码的不同文本片段。每一块都应该“激发”刮刀方法的各个部分。

    这样,您就可以完全删除对任何外部(文件和网页)的依赖关系。而且您的测试将更容易单独维护,因为它们不再依赖于外部文件。您的单元测试执行速度(稍微快一点);)

        3
  •  3
  •   jamiew    15 年前

    对于我的Ruby+机械化scraper,我一直在尝试集成测试,这些测试可以透明地针对尽可能多的目标页面版本进行测试。

    在测试中,除了手动保存的“原始”副本外,我正在重载scraper http fetch方法,以便自动重新缓存页面的新版本。然后,每个集成测试都针对:

    • 原始手动保存的页面(有点像单元测试)
    • 最新版本的网页
    • 立即从网站上获取实时副本(脱机时跳过此副本)

    …如果它们返回的字段数不同(例如,它们更改了缩略图类的名称),但仍然提供了一些抵御测试破坏的弹性,因为目标站点已关闭。

        4
  •  2
  •   Norman Ramsey    15 年前

    创造 你的单元测试,你需要知道你的刮刀是如何工作的,以及你认为它应该提取什么样的信息。使用简单的网页作为单元测试可能是可以的,这取决于刮刀的复杂性。

    对于回归测试,您应该绝对将文件保存在磁盘上。

    但是,如果您的最终目标是抓取Web,那么您还应该保留常见查询和返回的HTML的记录。这样,当应用程序失败时,可以快速捕获所有过去感兴趣的查询(使用say wget curl )并找出HTML是否发生了变化以及如何发生了变化。

    换句话说,回归测试既针对已知HTML,也针对已知查询中的未知HTML。如果发出一个已知的查询,并且返回的HTML与数据库中的HTML相同,则不需要测试两次。

    顺便说一下,我已经 许多的 更幸运的是屏幕抓取,自从我不再尝试抓取原始HTML,而是开始抓取 w3m -dump ,这是ASCII码,所以更容易处理!

        5
  •  2
  •   David Anderson    15 年前

    你得想想你在刮什么。

    • 静态HTML(不一定要剧烈更改并破坏scraper的HTML)
    • 动态HTML(松散术语,可能会发生巨大变化的HTML)
    • 未知(无论格式如何,从中提取特定数据的HTML)

    如果HTML是静态的,那么我只需要在磁盘上使用几个不同的本地副本。由于您知道HTML不一定会发生剧烈的变化并破坏您的scraper,所以您可以自信地使用本地文件编写测试。

    如果HTML是动态的(同样是松散术语),那么您可能希望继续进行测试并在测试中使用实时请求。如果您在这个场景中使用本地副本,并且测试通过,那么您可能期望活动HTML也这样做,但是它可能会失败。在这种情况下,通过每次对实时HTML进行测试,您可以在部署之前立即知道屏幕刮刀是否达到标准。

    现在,如果您只是不关心HTML的格式、元素的顺序或结构,因为您只是基于某种匹配机制(regex/other)拉出单个元素,那么本地副本可能很好,但您可能仍然希望倾向于对活动HTML进行测试。如果活动HTML发生了变化,特别是您正在寻找的部分内容,那么如果您使用的是本地副本,那么您的测试可能会通过,但come部署可能会失败。

    我的观点是,如果可以的话,可以对实时HTML进行测试。当实时HTML可能失败时,这将阻止本地测试通过,反之亦然。我不认为有一个最佳实践与刮网器,因为刮网器本身是不寻常的小窃听器。如果一个网站或Web服务没有公开一个API,那么screensraper就是一种获取所需数据的廉价解决方案。

        6
  •  1
  •   Brian Agnew    15 年前

    你的建议听起来很明智。我可能会有一个合适的测试HTML文件目录,以及每个文件的预期数据。您可以在遇到已知有问题的页面时用它们进一步填充这些页面,以形成完整的回归测试套件。

    您还应该为实际会话HTTP执行集成测试(不仅包括成功的页面提取,还包括404错误、无响应的服务器等)。

        7
  •  1
  •   Eric J.    15 年前

    我认为这取决于您需要运行多少个不同的测试。

    如果您需要在单元测试中检查大量不同的内容,那么最好在测试初始化过程中生成HTML输出。它仍然是基于文件的,但是您有一个可扩展的模式:

    Initialize HTML file with fragments for Test A
    Execute Test A
    Delete HTML file
    

    这样,当您在路上添加测试zzz时,您将有一种一致的方法来提供测试数据。

    如果您只运行有限数量的测试,并且它将保持这种状态,那么一些预先编写的静态HTML文件就可以了。

    当然,按照Rich的建议做一些集成测试。

        8
  •  1
  •   48klocs    15 年前

    你在创造一个外部依赖,这将是脆弱的。

    为什么不创建一个用一堆资源文件填充的testcontent项目呢?复制粘贴源HTML到资源文件中,然后您可以在单元测试中引用它们。

        9
  •  1
  •   Armentage    15 年前

    听起来这里有几个组件:

    • 获取HTML内容的内容
    • 一种能剥去颖壳,只产生必须擦掉的文本的东西。
    • 实际查看内容并将其转换为数据库的内容/无论什么

    您应该独立地测试(并且可能)实现scraper的这些部分。

    你没有理由不能从任何地方获取内容(即没有HTTP)。

    除了刮擦,没有理由不想把谷壳剥下来。

    没有理由只通过抓取将数据存储到数据库中。

    所以…作为一个大型程序,没有理由构建和测试所有这些代码片段。

    然后又…也许我们已经把事情复杂化了?

        10
  •  0
  •   C. Ross trotttrotttrott    15 年前

    除了一个或两个测试之外,您可能应该在磁盘上查询一个静态页面。但是不要忘记那些接触到网络的测试!

        11
  •  0
  •   Rich Seller    15 年前

    就您的单元测试而言,我不明白HTML从何而来并不重要。 澄清一下:您的单元测试正在处理HTML内容,这些内容来自何处无关紧要,因此从文件中读取这些内容对于单元测试来说是可以的。正如您在评论中所说,您肯定不希望每次测试都访问网络,因为这只是开销。

    您可能还需要添加一两个集成测试来检查您是否正确地处理了URL(即您能够连接和处理外部URL)。