如何使用黄瓜在场景之间共享状态

时间:2012-06-22 21:17:07

标签: ruby tdd cucumber bdd

我有一个功能“从外部网站导入文章”。 在我的第一个场景中,我测试从外部网站导入链接列表。

Feature: Importing articles from external website
  Scenario: Searching articles on example.com and return the links
    Given there is an Importer
    And its URL is "http://example.com"
    When we search for "demo"
    Then the Importer should return 25 links
    And one of the links should be "http://example.com/demo.html"

在我的步骤中,我在@result数组中有25个链接。

在我的第二个场景中,我想采用其中一个链接并测试我正确解析文章的事实。

现在显然我不想每次都去外部网站,特别是现在第一个场景通过了。

我如何继续这里,以便我可以继续测试而不需要为第一个场景发出HTTP请求?或者我应该运行一次并将@result数组保留在其他方案中,以便我可以继续使用实际的结果集吗?

6 个答案:

答案 0 :(得分:8)

这是故意很难做到的!在测试之间共享状态通常是非常糟糕的事情,尤其是因为它会强制您的测试按顺序运行(您的第一个场景必须在后续场景之前运行,而不是Cucumber明确支持的内容)。

我的建议是重新考虑你的测试策略。在测试中使用外部服务是使它们运行缓慢且不可靠的好方法(当外部服务出现故障时会发生什么?)。在这种情况下,我建议使用webmockvcr之类的内容来创建外部网站的虚假版本,返回与您对真实网站的期望相同的响应,但你可以随心所欲地打多少次而不用担心性能或不可用。

答案 1 :(得分:3)

我发现技术上可以使用

@@ global_variable在步骤定义中共享全局状态。

然而,就像其他人一样,这可能不是一个好主意。

我试图避免在类似方案中重复登录步骤。同样,这可能不是一个好习惯。在必要时使用技巧

答案 2 :(得分:2)

您不应在方案之间共享状态。场景描述了整个系统的预期行为,并且应该可以仅运行一个场景。例如。如果您运行了整个测试套件,并且发现单个场景失败,那么您应该只能运行该场景以调查出现了什么问题。

您的问题出现是因为您尝试联系外部系统。这是不可取的。它不仅使您的测试套件运行速度更慢,而且还使测试依赖于您无法控制的外部系统。如果外部系统未运行,则表示测试未运行。如果外部测试不包含您期望的数据,即使您自己的系统中没有错误,您的测试也会失败。最终,您可以根据预期在外部系统中的内容来控制测试,而不是根据您需要测试的内容来控制外部系统中的内容。

相反,你应该嘲笑外部系统,并让你的场景控制模拟系统将提供什么:

Scenario: Query external system
    # These two lines setup expected data in a mocked version of the external system
    Given there the system x contains an article named "y"
    And the article contains the text "Lorep ipsum"
    When I query for article "y"
    Then I should see the text "Lorem ipsum"

此方案独立于外部系统中的任何实际数据,因为它明确指定了需要的内容。更重要的是,它清楚地描述了您自己的系统应该如何表现。

该表格中的场景也可以传达给利益相关者,他们可以在不事先了解这些外部系统中存在的任何测试数据的情况下验证场景。

可能需要一些时间来运行正确的框架,但最终,它将是值得的。

答案 3 :(得分:0)

我使用的是文件。我有一个案例来创建一个新用户,然后我想注销并使用其他功能中的同一用户重新登录。

我使用以下内容生成用户:

@randomName = [*('a'..'z')].sample(8).join

然后我将用户保存到文件中:

File.open("randomName.txt", 'w') {|f| f.write("#{@randomName}") }

稍后,当我需要其他功能中的数据时,我使用:

@randomName = data = File.read("randomName.txt")

答案 4 :(得分:0)

使场景依赖或在场景之间共享数据不是一个好习惯。

一些解决方案 1)Cucumber提供背景标记来为每个场景运行前置条件。

2)Cucumber提供钩子@Before和@after,可以为每个场景定制。

答案 5 :(得分:0)

我还没有发现任何让我想要使用这些DI小框架的东西。我只是在存储会话数据的类中创建了一个静态初始化程序,并让所有步骤定义类都对该类进行了扩展。它可以工作,我不必在项目中添加任何其他库。

id

如果您需要随时间变化的数据,只需声明它们为非静态。