【问题标题】:Testing: How to test that view contains desired data测试:如何测试包含所需数据的视图
【发布时间】:2012-05-18 21:48:47
【问题描述】:

假设厨师可以制作食谱,副厨师可以制作必须得到主厨批准的食谱。

您想测试一下,当主厨查看她的主页时,她会看到她自己创建的食谱。您还想测试她是否看到有等待她批准的食谱。

我可以想到两种方法来做到这一点:

  1. 测试视图是否包含某些字词,例如“您的食谱”和“正在等待您批准的食谱”
  2. 向您正在使用的 html 元素添加不必要的属性,以便您可以检查具有“id=recipe_1”或“data-for-the-sake-of-testing=1”的元素

我非常不喜欢这两种方法。

为什么方法 #1 很烂

  1. 难以置信的脆弱测试。每次您想对副本进行小幅更新时,测试都会中断。
  2. i18n?这种方法将如何发挥作用?

可能还有更多的原因,但这两个是相当大的。

为什么方法 #2 很烂

为了测试而有多余的标记是多么令人讨厌!用户不应为了测试而增加下载大小。


对此有什么好的方法?我很想听听任何替代方案,无论您使用哪种语言。我主要使用 Ruby、Test::Unit、Minitest、RSpec 和 Cucumber(尽管我的 Cuke 技能已经过时),但如果其他语言/框架弄明白了,我也很想看看他们在做什么。

【问题讨论】:

  • 这些不是链接吗?例如href=ddd?recipeid=1234?并且您可以测试应该存在的所有链接(并且不存在其他链接),因此您需要有一个独立的配方列表(例如来自以前的测试用例或数据库查询)..
  • 在这个例子中,它们可能是链接。但不一定。 URL 可以更改,因此也有些脆弱。 (i18n 可以更改 URL,也可以将其从“/recipes?id=1”重组为“/recipes/1”。)但是,我对非必要链接文本的一般情况更感兴趣。如何测试?
  • 如果应用程序可以解码“/recipes/1”链接,那么显然是可以做到的 => 所以你可以编写一个测试来做到这一点。如果需要,可以将本地化字符串追溯到原始 id.. 但我没有写一本关于测试的书,所以我不知道什么是“正确”的方法;)

标签: view tdd integration-testing bdd


【解决方案1】:

使用页面范例。

尽可能在能力级别(高级别)以人性化的方式表述这些步骤,并使用具体示例。例如,如果我使用 Cucumber,我可能会说:

鉴于副厨师长已经为青蛙馅饼制作了食谱
当厨师寻找要批准的食谱时
那么青蛙派的食谱应该在列表中。

在这些步骤的代码中,实例化或找到您正在寻找的特定页面,其中该页面是表示页面功能的对象。然后,该页面可以拥有所有用户可以对页面执行的操作 - 查找食谱、批准食谱、移动到另一个页面等。

这样,如果您需要更改步骤的底层代码,您只需在一个地方更改它,特定页面的所有更改都会一起进行。因为您已经根据您要交付的功能来表述该场景,所以该场景不太可能需要进行太多更改(除非您发现您的业务需要与您所交付的功能不同的功能)。

这也适用于基于窗口的应用程序,每个小部件或模块都是一个特定页面。

额外的 id 也可以用于测试。有时设计师也喜欢使用它们。

【讨论】:

    【解决方案2】:

    我看到至少两个选项:

    1. 避免通过 UI 测试业务逻辑。编写返回纯数据结构的“服务”或“用例控制器”对象。换句话说,你为你的系统构建了一个 API。您的单元测试通过 API 访问系统。您的 UI 通过相同的 API 访问系统,但是视图中应该几乎没有逻辑。请参阅http://www.confreaks.com/videos/759-rubymidwest2011-keynote-architecture-the-lost-yearshttp://www.cleancoders.com/codecast/clean-code-episode-7/show

    2. 使用“page object”模式。编写一个对象,读取您的应用程序生成的 HTML 代码,对其进行解析,并通过 getter 提供有趣的数据。这将使您的 test 代码清晰。你的反对意见可能是你仍然有问题#2。事实上,我不认为这真的是一个问题。如果您使用结构化 HTML 标记,那么提取您需要的信息应该相当容易。如果您将 ID 附加到页面的关键元素会容易得多;在您的示例中,我将有一个 id="my-recipes" 的 div 和另一个 id="to-be-approved" 的 div。这应该足够了;使用 xpath 或 css 选择器应该很容易找到其他任何东西。为什么你觉得这令人反感?这些 ID 可能对其他用途有用,例如使用不显眼的 JavaScript 附加行为或使用 CSS 样式表附加样式。

    【讨论】:

    • 很好的答案和链接!我需要一些时间来处理它。但要回答您的问题:添加多余的 ID仅用于测试感觉就像我现在正在为我而不是我的客户编写代码。我的客户现在的文件大小增加了,但对他们没有任何好处。 如果 JS 或 CSS 需要连接到元素上,那么(可以说可以忽略不计,我明白了)增加的文件大小对客户有好处。
    • 谢谢你。我理解您的担忧,但我仍然觉得拥有经过良好测试的产品确实有利于您的客户 :-)
    【解决方案3】:

    使用 #2,可能使用简短的 cmets(没有 i18n 问题并且对最终用户不可见):

    <!-- APPROVAL -->
    

    documentation of simpletest 对此有很好的理解:

    下一个机会,看看电路板,也许是主板 您现在正在查看的计算机。在大多数板上,您将 找到奇怪的空洞,或没有任何连接的焊点或 可能是没有明显功能的插针或插座。机会是 其中一些用于扩展和变化,但大多数 其余的将用于测试。

    如果少量多余的标记使您的产品更可测试和更可靠,那么就接受它吧!

    【讨论】:

    • #2 明显优于 #1,但还是让我感叹。虽然有趣的是 EE 不得不留下多余的针脚,但我们在数字世界中也许能够想出一个更优雅的解决方案。
    • HTML cmets 很难在单元测试中使用。最好使用 id 或 class 属性,以便您可以在 xpath 查询中使用它们。
    • assertPattern('#RECIPES_FOR_APPROVAL#', $output) 似乎并不难。使您的测试标签明确,而不是使用可以/应该随您的业务需求而改变的 id 和类属性似乎更清晰。
    【解决方案4】:

    我个人尽量不测试视图。我的意思是生成的标记,因为这些测试看起来很脆弱。

    相反,我专注于“数据提供者”方面,如果 MVC Web 框架是 Controller。一旦控制器被单元测试覆盖,检查控制器准备了什么类型的数据,你就很安全了。您创建的视图很容易测试,只需运行应用程序并查看它是否正常。

    尽管如此,还是有一些视图测试方法。第一个是基于 Selenium Driver 的“端到端”测试模拟。它运行浏览器并初始化对您的应用程序的请求。测试正在检查输出 HTML。测试登录到“已知”版本,这意味着测试知道当前本地化是EN,例如。

    您应该基本上结合使用 HTML 标记值(“Recipies”)的方法,否则使用 HTML 元素 id 或类。我不会为测试添加任何额外的标记。

    您可以尝试的另一种方法是批准测试。我相信有一个 Ruby 驱动程序 - http://approvaltests.sourceforge.net/。获得批准后,您可以呈现视图并将 HTML 保存为黄金母版。如果 View 已更改,测试将失败。它比 Selenium 测试更容易实现。

    【讨论】:

      猜你喜欢
      • 2013-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多