如何使用行为驱动开发在 Drupal 中与 Behat

以人类可读的格式测试您的 Drupal 网站的功能。
140 位读者喜欢这个。
Team checklist and to dos

行为驱动开发是为代码编写测试的好方法,因为它使用的语言是真人可以理解的。一旦您了解 BDD 及其好处,您可能希望在您的下一个项目中实施它。让我们看看如何在 Drupal 中使用 BehatMink 扩展来实施 BDD。

安装和配置工具

由于使用 Composer 管理 Drupal 站点的依赖项是一个很好的实践,因此使用它来安装 BDD 测试的工具:Behat、Mink 和 Behat Drupal Extension。Behat Drupal Extension 将 Behat 和 Mink 列在其依赖项中,因此您可以通过安装 Behat Drupal Extension 包来获取所有工具

composer require drupal/drupal-extension --dev

Mink 允许您以人类可读的格式编写测试。例如

假设我是一个注册用户,
当我访问主页时,
那么我应该看到个性化的新闻提要

因为这些测试应该模拟用户交互,所以您可以假设它们将在 Web 浏览器中执行。这就是 Mink 发挥作用的地方。有各种浏览器模拟器,例如 Goutte 和 Selenium,它们都表现不同,并且具有非常不同的 API。Mink 允许您编写一次测试并在不同的浏览器模拟器中执行它。用外行的话来说,Mink 允许您以编程方式控制浏览器以模拟用户的操作。

现在您已经安装了工具,您应该有一个可用的 behat 命令。如果您运行它

./vendor/bin/behat

您应该会收到一个错误,例如

FeatureContext context class not found and can not be used

首先初始化 Behat

./vendor/bin/behat --init

这将创建两个文件夹和一个文件,我们稍后将重新访问;目前,在没有额外参数的情况下运行 behat 不应产生错误。相反,您应该看到类似于这样的输出

No scenarios
No steps
0m0.00s (7.70Mb)

现在您可以编写您的第一个测试,例如,验证网站访问者是否可以使用站点范围的联系表单留言。

编写测试场景

默认情况下,Behat 将在项目初始化时创建的 features 文件夹中查找文件。该文件夹内的文件应具有 .feature 扩展名。让我们测试站点范围的联系表单。在 features 文件夹中创建一个文件 contact-form.feature,内容如下


Feature: Contact form
  In order to send a message to the site administrators
  As a visitor
  I should be able to use the site-wide contact form

  Scenario: A visitor can use the site-wide contact form
    Given I am at "contact/feedback"
    When I fill in "name" with "John Doe"
    And I fill in "mail" with "john@doe.com"
    And I fill in "subject" with "Hello world"
    And I fill in "message" with "Lorem Ipsum"
    And I press "Send message"
    Then I should see the text "Your message has been sent."

Behat 测试以 Gherkin 编写,Gherkin 是一种人类可读的格式,遵循上下文-操作-结果模式。它由几个特殊的关键字组成,这些关键字在解析后将执行命令,以模拟用户与网站的交互。

以关键字 GivenWhenThen 开头的句子分别表示上下文、操作和结果。它们被称为步骤,应该从执行操作的用户的角度编写。Behat 将读取它们并执行相应的步骤定义。(稍后详细介绍。)

此示例指示浏览器访问“contact/feedback”链接下的页面,填写一些字段值,按下一个按钮,并检查页面上是否存在消息以验证操作是否有效。运行测试;您的输出应类似于这样

1 scenario (1 undefined)
7 steps (7 undefined)
0m0.01s (8.01Mb)

 >> default suite has undefined steps. Please choose the context to generate snippets:

  [0] None
  [1] FeatureContext
 >

在提示符下键入 0 以选择“无”选项。这验证了 Behat 找到了测试并尝试执行它,但它正在抱怨未定义的步骤。这些是步骤定义,即 PHP 代码,它将执行完成步骤所需的任务。您可以通过运行以下命令检查哪些步骤定义可用

./vendor/bin/behat -dl

目前没有步骤定义,因此您不应看到任何输出。您可以编写自己的步骤定义,但现在,您可以使用 Mink 扩展和 Behat Drupal Extension 提供的一些步骤定义。在与 Features 文件夹相同的级别(而不是在其中)创建一个 behat.yml 文件,内容如下

default:
  suites:
    default:
      contexts:
        - FeatureContext
        - Drupal\DrupalExtension\Context\DrupalContext
        - Drupal\DrupalExtension\Context\MinkContext
        - Drupal\DrupalExtension\Context\MessageContext
        - Drupal\DrupalExtension\Context\DrushContext
  extensions:
    Behat\MinkExtension:
      goutte: ~

步骤定义通过上下文提供。当您初始化 Behat 时,它创建了一个没有步骤定义的 FeatureContext。在上面的示例中,我们正在更新配置文件,以包含此空上下文以及 Drupal Behat Extension 提供的其他上下文。再次运行 ./vendor/bin/behat -dl 会生成 120 多个步骤的列表供您使用;这是一个修剪后的输出版本

default | Given I am an anonymous user
default | When I visit :path
default | When I click :link
default | Then I (should )see the text :text

现在您可以执行许多操作。使用 ./vendor/bin/behat 再次运行测试。测试应该失败,并显示类似于以下的错误

  Scenario: A visitor can use the site-wide contact form 	# features/contact-form.feature:8
	And I am at "contact/feedback"                       	# Drupal\DrupalExtension\Context\MinkContext::assertAtPath()
	When I fill in "name" with "John Doe"                	# Drupal\DrupalExtension\Context\MinkContext::fillField()
	And I fill in "mail" with "john@doe.com"             	# Drupal\DrupalExtension\Context\MinkContext::fillField()
	And I fill in "subject" with "Hello world"           	# Drupal\DrupalExtension\Context\MinkContext::fillField()
  	Form field with id|name|label|value|placeholder "subject" not found. (Behat\Mink\Exception\ElementNotFoundException)
	And I fill in "message" with "Lorem Ipsum"           	# Drupal\DrupalExtension\Context\MinkContext::fillField()
	And I press "Send message"                           	# Drupal\DrupalExtension\Context\MinkContext::pressButton()
	Then I should see the text "Your message has been sent." # Drupal\DrupalExtension\Context\MinkContext::assertTextVisible()

--- Failed scenarios:

	features/contact-form.feature:8

1 scenario (1 failed)
7 steps (3 passed, 1 failed, 3 skipped)
0m0.10s (12.84Mb)

输出显示前三个步骤(访问联系页面并填写姓名和主题字段)已成功。但是当用户尝试输入主题时,测试失败,然后它跳过其余步骤。这些步骤要求您使用呈现表单字段的 HTML 标记的 name 属性。

当我创建测试时,我特意使用了姓名和地址字段的正确值,以便它们能够通过。如有疑问,请使用浏览器的开发者工具检查源代码,并找到您应该使用的正确值。通过这样做,我发现主题应该使用 subject[0][value],消息应该使用 message[0][value]。当我更新我的测试以使用这些值并再次运行时,它应该会顺利通过,并产生类似于以下的输出

1 scenario (1 passed)
7 steps (7 passed)
0m0.29s (12.88Mb)

成功!测试通过了!如果您想知道,我正在使用 Goutte 浏览器。它是一个命令行浏览器,用于将其与 Behat 一起使用的驱动程序作为 Behat Drupal Extension 包的依赖项安装。

其他需要注意的事项

如上所述,BDD 测试应该从执行操作的用户的角度编写。用户不会以 HTML name 属性来思考。这就是为什么使用 subject[0][value]message[0][value] 编写测试既晦涩难懂,又不是很用户友好。您可以通过在 features/bootstrap/FeatureContext.php 中创建自定义步骤来改进这一点,这是在 Behat 初始化时生成的。

此外,如果您多次运行测试,您会发现它开始失败。这是因为 Drupal 默认情况下对每小时提交次数限制为五次。每次运行测试时,就像真实用户在执行操作一样。一旦达到限制,您将在 Drupal 界面上收到错误。测试失败是因为缺少预期的成功消息。

这说明了调试测试的重要性。有一些步骤可以帮助解决这个问题,例如 Then print last drush outputThen I break。更好的是使用真正的调试器,例如 Xdebug。您还可以安装其他软件包,这些软件包提供更多专门用于调试目的的步骤定义,例如 BehatchNuvole's 扩展。例如,您可以配置 Behat 在测试失败时(如果您的驱动程序提供此功能)拍摄浏览器状态的屏幕截图。

关于驱动程序和浏览器模拟器,Goutte 不支持 JavaScript。如果某个功能依赖于 JavaScript,您可以使用 Selenium2Driver 结合 Geckodriver 和 Firefox 来测试它。每个驱动程序和浏览器都有不同的功能和特性。例如,Goutte 驱动程序提供对响应的 HTTP 状态代码的访问,但 Selenium2Driver 不提供。(您可以阅读有关 Mink 和 Behat 中的驱动程序的更多信息。)为了让 Behat 拾取启用 JavaScript 的驱动程序/浏览器,您需要使用 @javascript 标签注释场景。示例

Feature:
  (feature description)

  @javascript
  Scenario: An editor can select the author of a node from an autocomplete field
    (list of steps)

另一个对 Drupal 站点有用的标签是 @api。这指示 Behat Drupal Extension 使用可以执行 Drupal 特有操作的驱动程序;例如,为您的测试创建用户和节点。虽然您可以按照注册过程创建用户并分配角色,但更简单的方法是简单地使用类似 Given I am logged in as a user with the "Authenticated user" role 的步骤。为了使此操作生效,您需要 指定您是要使用 Drupal 驱动程序还是 Drush 驱动程序。确保相应地更新您的 behat.yml 文件。例如,要使用 Drupal 驱动程序

default:
  extensions:
    Drupal\DrupalExtension:
      blackbox: ~
      api_driver: drupal
      drupal:
        drupal_root: ./relative/path/to/drupal

我希望这个 Drupal 中 BDD 测试的介绍对您有所帮助。如果您有任何问题,请随时在下面添加评论,发送电子邮件至 {我的名字}@{我的姓氏}.me 或在 Twitter 上发推文 @dinarcon


Mauricio Dinarte 将在 2019 年 4 月 8-12 日在西雅图 DrupalCon 上展示 Drupal 8 中使用 Behat 的行为驱动开发


接下来阅读什么
Photo of Mauricio Dinarte
Mauricio Dinarte 是一位 Drupal 和 React JS 开发人员,对教学充满热情。多年来,他在美国和欧洲的不同会议上,包括 DrupalCon,举办了 30 多个会议和研讨会。通过他的 UnderstandDrupal.com 项目,他希望通过用英语、西班牙语和法语教授 Drupal 和相关技术来打破语言障碍。

评论已关闭。

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.