behat开始使用behat


备注

本节概述了什么是开发人员可能想要使用它的原因。

它还应该提到behat中的任何大型主题,并链接到相关主题。由于behat的文档是新的,您可能需要创建这些相关主题的初始版本。

从Behat开始

Behat提供Gherkin Syntax ,这是一种人类可读的格式。它允许您轻松描述您的用户故事。

要从Behat开始,您应该使用Composer安装它,然后初始化您的测试文件:

$ composer require --dev behat/behat="^3.0.5"

$ ./vendor/bin/behat --init

+d features # place your *.feature files here
+d features/bootstrap # place your context classes here
+f features/bootstrap/FeatureContext.php # place your definitions, transformations and hooks here
 

默认情况下,您将测试文件放在features/ 文件夹中,并具有扩展名.feature

每个测试文件都应定义应用程序的特定功能。功能被分解为一系列场景,并包含一系列需要成功执行以使场景通过的步骤。每个场景都需要传递才能传递一个功能。

# features/PartyHarmony.feature
Feature: Party Harmony
    As a Dungeon Master, I want to ensure harmony and mutual trust, so that
    the party can work together as a team

    Scenario: Teach members to respect each others property
        Given that the Wizard has 10 cookies
        And the Bard eats 1 cookie
        Then the Bard is mysteriously on fire
 

要运行测试,请直接执行Behat二进制文件。我们可以选择指定要运行的功能文件(否则运行所有测试)。此功能文件将因未定义的步骤错误而失败(因为我们尚未定义这些步骤的含义):

$ ./vendor/bin/behat features/PartyHarmony.feature
Feature: Party Harmony
    As a Dungeon Master, I want to ensure harmony and mutual trust, so that
    the party can work together as a team

  Scenario: Teach members to respect each others property # features/PartyHarmony.feature:6
    Given that the Wizard has 10 cookies
    And the Bard eats 1 cookie
    Then the Bard is mysteriously on fire

1 scenario (1 undefined)
3 steps (3 undefined)
0m0.01s (10.49Mb)

--- FeatureContext has missing steps. Define them with these snippets:

    /**
     * @Given that the Wizard has :arg1 cookies
     */
    public function thatTheWizardHasCookies($arg1)
    {
        throw new PendingException();
    }

    /**
     * @Given the Bard eats :arg1 cookie
     */
    public function theBardEatsCookie($arg1)
    {
        throw new PendingException();
    }

    /**
     * @Then the Bard is mysteriously on fire
     */
    public function theBardIsMysteriouslyOnFire()
    {
        throw new PendingException();
    }
 

场景中的每个步骤都从上下文PHP文件运行一段代码(不同的功能测试可以加载不同的上下文)。我们可以复制Behat建议的例子或创建我们自己的例子。该步骤与正则表达式检查匹配。所以,如果我们实施

<?php
# 
class FeatureContext {
    /**
     * @Given that the wizard has :num cookies
     */
    public function wizardHasCookies($num) {
        // $this->wizard is a pre-existing condition.... like syphilis
        $this->wizard->setNumberOfCookies($num);
    }

    /**
     * @Given the Bard eats :num cookie
     */
    public function theBardEatsCookie($num)
    {
        $this->bard->consumeCookies($num);
    }

    /**
     * @Then the Bard is mysteriously on fire
     */
    public function theBardIsMysteriouslyOnFire() {
        PHPUnit_Framework_Assert::assertTrue(
            $this->bard->isBardOnFire()
        );
    }
}
 

你会注意到PHPUnit_Framework_Assert 的使用。 Behat没有它自己的断言系统,所以你可以使用你想要的任何一个。

现在运行测试将执行实际代码,我们可以测试是否所有内容都通过:

$ ./vendor/bin/behat features/PartyHarmony.feature
Feature: Party Harmony
    As a Dungeon Master, I want to ensure harmony and mutual trust, so that
    the party can work together as a team

  Scenario: Teach members to respect each others property # features/PartyHarmony.feature:6
    Given that the Wizard has 10 cookies                  # FeatureContext::thatTheWizardHasCookies()
    And the Bard eats 1 cookie                            # FeatureContext::theBardEatsCookie()
    Then the Bard is mysteriously on fire                 # FeatureContext::theBardIsMysteriouslyOnFire()

1 scenario (1 passed)
3 steps (3 passed)
0m0.01s (10.59Mb)
 

捕获电子邮件

功能测试还可以包括测试离开环境的流程,例如外部API调用和电子邮件。

例如,假设您在功能上测试了您网站的注册过程。此过程的最后一步涉及发送带有激活链接的电子邮件。在访问此链接之前,该帐户尚未完全注册。你想要测试两个:

  1. 电子邮件将正确发送(格式化,占位符替换等),以及
  2. 激活链接有效

现在,您可以测试电子邮件发送,但使用IMAP或POP客户端从邮箱中检索已发送的电子邮件,但这意味着您还要测试Internet连接,远程电子邮件服务器以及传送中可能出现的任何问题(垃圾邮件检测)例如)。

更简单的解决方案是使用本地服务来捕获传出的SMTP连接并将发送的电子邮件转储到磁盘。

几个例子是:

smtp-sink - 与Postfix捆绑在一起的实用程序。

# Stop the currently running service
sudo service postfix stop

# Dumps outgoing emails to file as "day.hour.minute.second"
smtp-sink -d "%d.%H.%M.%S" localhost:2500 1000

# Now send mails to your local SMTP server as normal and they will be
# dumped to raw text file for you to open and read

# Run your functional tests
vendor/bin/behat
 

不要忘记杀死smtp-sink 并在之后重启你的postfix服务:

# Restart postfix
sudo service postfix start
 

FakeSMTP - 一种基于Java的客户端,用于捕获外发邮件

# -b = Start without GUI interface
# -o = Which directory to dump your emails to
$ java -jar fakeSMTP.jar -b -o output_directory_name
 

或者,您可以使用提供此服务的远程服务(如mailtrap),但您的测试依赖于Internet访问。

用貂皮扩展Behat

Mink为Web驱动程序(如Goutte和Selenium)提供了一个界面,以及一个MinkContext ,当扩展时,它为我们的步骤提供了额外的Web语言。

要安装Mink(和默认的Goutte驱动程序):

$ composer require --dev behat/mink-extension="^2.0"
$ composer require --dev behat/mink-goutte-driver="^1.0"
 

然后使用MinkContext 扩展您的上下文:

<?php
use Behat\MinkExtension\Context\MinkContext;

class FeatureContext extends MinkContext … {
    …
}
 

您可以使用以下命令查看Behat安装中可用的整个语法列表:

$ ./vendor/bin/behat -dl

Given /^(?:|I )am on "(?P<page>[^"]+)"$/
 When /^(?:|I )reload the page$/
 When /^(?:|I )move backward one page$/
 When /^(?:|I )move forward one page$/
 When /^(?:|I )press "(?P<button>(?:[^"]|\\")*)"$/
 When /^(?:|I )follow "(?P<link>(?:[^"]|\\")*)"$/
 When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/
 

然后,您需要配置Mink以指示要测试的网站所在的位置以及要使用的Web驱动程序(默认情况下为Goutte):

# ./behat.yml
default:
    extensions:
        Behat\MinkExtension:
            base_url: "[your website URL]"
            sessions:
                default:
                    goutte: ~
 

以下是仅使用Mink提供的步骤的方案示例:

# ./features/Authentication.feature
Feature: Authentication
    As a security conscious developer I wish to ensure that only valid users can access our website.

    Scenario: Login in successfully to my website
        When I am on "/login"
        And I fill in "email" with "my@email.com"
        And I fill in "password" with "my_password"
        And I press "Login"
        Then I should see "Successfully logged in"

    Scenario: Attempt to login with invalid credentials
        When I am on "/login"
        And I fill in "email" with "my@email.com"
        And I fill in "password" with "not_my_password"
        And I press "Login"
        Then I should see "Login failed"
 

您现在可以通过Behat运行该功能来测试它:

./vendor/bin/behat features/Authentication.feature
 

您可以使用MinkContext 创建自己的步骤以MinkContext 常见步骤(例如,登录是一种非常常见的操作):

Feature: Authentication
    As a security conscious developer I wish to ensure that only valid users can access our website.

    Scenario: Login in successfully to my website
        Given I login as "my@email.com" with password "my_password"
        Then I should see "Successfully logged in"

    Scenario: Attempt to login with invalid credentials
        Given I login as "my@email.com" with password "not_my_password"
        Then I should see "Login failed"
 

您需要使用MinkContext 扩展上下文文件,以访问Web驱动程序和页面交互:

<?php
use Behat\MinkExtension\Context\MinkContext;

class FeatureContext extends MinkContext {
    /**
      * @Given I login as :username with password :password
      */
    public function iLoginAsWithPassword($username, $password) {
        $this->visit("/login");
        $this->fillField("email", $username);
        $this->fillField("password", $password);
        $this->pressButton("Login");
    }
}
 

Mink还在大多数预先提供的调用中提供CSS选择器,允许您使用以下结构识别页面上的元素:

When I click on "div[id^='some-name']"
And I click on ".some-class:first"
And I click on "//html/body/table/thead/tr/th[first()]"
 

功能测试作为用户故事

功能测试最好描述为用户故事的测试。如果您在通常遵循以下模式之前处理过用户故事:

As a [role], I want to [desire], so that [benefit/desired outcome]
 

对于以下示例,我们将使用此用户故事作为示例:

As a Dungeon Master, I want to ensure harmony and mutual trust, so that
the party can work together as a team
 

在PHP功能测试的两种最流行的测试框架是贝哈特PHPSpec

安装或设置

贝哈特/水貂

使用composer安装(用于其他方法检查)behat.org如果你使用linux,请确保你已经安装了php-curl(正常的curl安装将无法正常工作)

Linux的

sudo apt-get install php5-curl
 

如果您使用的是Windows ,请确保安装了PHP,Curl和Git。您可以在以下链接中找到以下内容:

你的composer.json将包含以下内容:

behat - composer.json

{
  "require": {
    "behat/behat": "dev-master",
    "behat/mink": "dev-master",
    "behat/mink-extension": "dev-master",
    "behat/mink-selenium2-driver": "dev-master",
    "phpunit/php-code-coverage": "dev-master",
    "phpunit/phpunit-mock-objects": "dev-master",
    "phpunit/phpunit": "dev-master"
  },
  "minimum-stability": "dev",
  "config": {
    "bin-dir": "bin/"
  }
}
 

(在Windows中保存composer.json文件时,需要选择“所有文件”作为文件类型和“ANSI”编码)

然后执行以下命令:

$ curl http://getcomposer.org/installer | php
$ php composer.phar install
 

在安装了Behat,Mink和Behat-Mink扩展之后,执行behat

执行behat

$ bin/behat
 

要激活Behat-Mink扩展,请使用:behat.yml使用以下内容创建文件“behat.yml”

behat.yml

default:
  suites:
    default:
      paths:
        features: %paths.base%/features/
        bootstrap: %paths.base%/features/bootstrap/
      contexts: 
        - FeatureContext
  extensions:
    Behat\MinkExtension:
      base_url: 'http://www.startTestUrl.de'
      selenium2:
        browser: firefox
        wd_host: "http://localhost:4444/wd/hub"
 

此文件将位于包含bin目录和behat链接的同一目录中。
另请注意,在yml文件中,请勿使用制表符进行缩进。使用空间。要获取behat-mink中可用命令的列表,请使用

$ bin/behat -di
 

使behat成为你系统的一部分

Linux的

转到您的Homedirectory并执行以下操作:

$ sudo vi .bashrc
 

并在目录末尾添加此行

export BEHAT_HOME=/home/*user*/path/to/behat
export PATH=$BEHAT_HOME/bin:$PATH
 

重新启动控制台或键入“source .bashrc”

视窗

浏览系统设置并将behat / bin路径添加到环境变量中

其他驱动程序必须安装Selenium,phantomjs,goutte等驱动程序。

设置测试数据

功能测试数据经常被修改。这可能导致测试套件的后续运行失败(因为数据可能已从其所处的原始状态更改)。

如果您使用支持迁移或种子设定的ORM或框架(如DoctrinePropelLaravel )设置数据源,则可以使用此设置在每次测试运行时创建一个包含Fixture数据的新测试数据库。

如果您当前没有使用其中一个(或等效的),您可以使用Phinx等工具快速设置新的测试数据库或为每次测试运行准备现有数据库(清理测试条目,将数据重置回原始状态) )。

# Install Phinx in your project
$ php composer.phar require robmorgan/phinx

$ php vendor/bin/phinx init
Phinx by Rob Morgan - https://phinx.org. version x.x.x
Created ./phinx.xml
 

将数据库凭据添加到./phinx.xml

$ php vendor/bin/phinx create InitialMigration
 

您可以使用文档中提供的语法指定数据库表的创建和填充方式。

然后,每次运行测试时都运行如下脚本:

#!/usr/bin/env bash

# Define the test database you'll use
DATABASE="test-database"

# Clean up and re-create this database and its contents
mysql -e "DROP DATABASE IF EXISTS $DATABASE"
mysql -e "CREATE DATABASE $DATABASE"
vendor/bin/phinx migrate

# Start your application using the test database (passed as an environment variable)
# You can access the value with $_ENV['database']
database=$DATABASE php -d variables_order=EGPCS -S localhost:8080

# Run your functional tests
vendor/bin/behat
 

现在,您的功能测试不会因数据更改而失败。

使用Mink和Selenium测试JavaScript

如果我们想在网站上测试JavaScript,我们需要使用比Goutte更强大的功能(通过Guzzle只是cURL)。有一些选项,如ZombieJSSeleniumSahi 。对于这个例子,我将使用Selenium。

首先,您需要安装Mink的驱动程序:

$ composer require --dev behat/mink-selenium2-driver="^1.2"
 

您还需要下载Selenium独立服务器 jar文件并启动它:

$ java -jar selenium-server-standalone-2.*.jar
 

我们还需要告诉Behat,当我们使用@javascript 标记来使用Selenium驱动程序并提供Selenium独立服务器的位置时。

# ./behat.yml
default:
    # …
    extensions:
        Behat\MinkExtension:
        base_url: "[your website URL]"
        sessions:
            # …
            javascript:
                selenium2:
                    browser: "firefox"
                    wd_host: http://localhost:4444/wd/hub
 

然后,对于您希望使用浏览器仿真运行的每个测试,您只需要在功能或方案的开头添加@javascript (或@selenium2 )标记。

# ./features/TestSomeJavascriptThing.feature
@javascript # or we could use @selenium2
Feature: This test will be run with browser emulation
 

然后可以通过Behat运行测试(与任何其他测试一样)。一个区别是,当测试运行时,它应该在运行Selenium独立服务器的计算机上生成一个浏览器窗口,然后执行所描述的测试。