快速开始教程:http://behat.org/en/latest/user_guide.html
用户指南:http://behat.org/en/latest/user_guide.html
PHPUnit 手册:https://phpunit.de/manual/current/zh_cn/appendixes.assertions.html
behat 结构:
behat.yml #套件配置,可设置套名称、包含解析回调PHP类文件列表、套件目录
例如:
default:
suites:
default:
paths: [ %paths.base%/features/default ]
contexts: [ FeatureContext ]
zhcn:
paths: [ %paths.base%/features/zhcn ]
contexts: [ ZhcnFeatureContext ]
features/ #features 文件根目录
features/bootstrap #上下文环境解析回调php类文件目录
features/default/xxx.feature #功能测试文件,放在default套件下
behat支持多语言配置文件:\vendor\behat\gherkin\i18n.php
可了解 behat 目前支持的关键词和语义:
'zh-CN' =>
array (
'and' => '并且<|而且<|同时<|*',
'background' => '背景',
'but' => '但是<|*',
'examples' => '例子',
'feature' => '功能',
'given' => '假设<|假如<|假定<|*',
'name' => 'Chinese simplified',
'native' => '简体中文',
'scenario' => '场景|剧本',
'scenario_outline' => '场景大纲|剧本大纲',
'then' => '那么<|*',
'when' => '当<|*',
),
关键包含的步骤,也是BDD建议使用的步骤 Givens,When,Then
一、Givens [假设]
1、创建记录(模型实例)或设置数据库。
Given there are no users on site
Given the database is clean
2、验证用户(无交互推荐的例外情况)“先前发生的事情”可以):
Given I am logged in as "Everzet"
3、使用Givens作为数据填充
Given there are users:
| username | password | email |
| everzet | 123456 | everzet@knplabs.com |
| fabpot | 22@222 | fabpot@symfony.com |
二、whens [条件](当一个步骤是描述关键行动用户执行,状态转变的时候)
1、与网页互动:
When I am on "/some/page"
When I fill "username" with "everzet"
When I fill "password" with "123456"
When I press "login"
2、与一些CLI库交互(调用命令和记录输出)
When I call "ls -la"
三、thens [观察结果] 然后步骤的目的是观察结果
1、响应 Given + When 后的内容
When I call "echo hello"
Then the output should be "hello"
2、检查一些外部系统是否收到预期的消息
When I send an email with:
"""
...
"""
Then the client should receive the email with:
"""
...
"""
四、and & but
1、使用多个Given When Then 的时候可用
Scenario: Multiple Givens
Given one thing
Given another thing
Given yet another thing
When I open my eyes
Then I see something
Then I don't see something else
使用 and & but 后:
Scenario: Multiple Givens
Given one thing
And another thing
And yet another thing
When I open my eyes
Then I see something
But I don't see something else
五、backgrounds [背景]
使您可以在单个功能中为所有场景添加一些上下文。背景就像一个无标题的场景,包含许多步骤。不同之处在于它运行时:背景是在每个场景之前运行的,但是在您的BeforeScenario Hooks之后。
Feature: Multiple site support
Background:
Given a global administrator named "Greg"
And a blog named "Greg's anti-tax rants"
And a customer named "Wilson"
And a blog named "Expensive Therapy" owned by "Wilson"
Scenario: Wilson posts to his own blog
Given I am logged in as Wilson
When I try to post to "Expensive Therapy"
Then I should see "Your article was published."
Scenario: Greg posts to a client's blog
Given I am logged in as Greg
When I try to post to "Expensive Therapy"
Then I should see "Your article was published."
六、scenario outlines [情景大纲]
为同一场景声明多个不同的值;
当出现多个类似场景测试,避免过多的复制和粘贴,可使用情景大纲允许我们通过使用带有占位符的模板来更简洁地表达这些;
情景大纲允许我们通过使用带有占位符的模板来更简洁地表达这些示例:(占位符 <start> <eat> <left> 在运行的时候将取 Examples 里面的对应的字段值,且按顺序,每行都运行)
Scenario Outline: Eating
Given there are <start> cucumbers
When I eat <eat> cucumbers
Then I should have <left> cucumbers
Examples:
| start | eat | left |
| 12 | 5 | 7 |
| 20 | 5 | 15 |
七、tables [数据表]
表作为步骤的参数可用于指定较大的数据集 - 通常作为 Given 的输入或来自 Then 的预期输出:
Scenario:
Given the following people exist:
| name | email | phone |
| Aslak | aslak@email.com | 123 |
| Joe | joe@email.com | 234 |
| Bryan | bryan@email.org | 456 |
使用表例子:
use Behat\Gherkin\Node\TableNode;
// ...
/**
* @Given the following people exist:
*/
public function thePeopleExist(TableNode $table)
{
foreach ($table as $row) {
// $row['name'], $row['email'], $row['phone']
}
}
将表作为TableNode对象注入定义中,您可以通过列(TableNode :: getHash()方法)或行(TableNode :: getRowsHash())获取散列。
八、multiline arguments [多行参数]
有时候,您希望将一个更丰富的的多行字符串数据结构,从前面步骤传递到下一个步骤定义。
这是多行参数设计的。它们在一个步骤之后立即写在行上,并作为最后一个参数传递给步骤定义方法。
多行参数有两种风格:talbes 或 pystrings
pystrings:
多行字符串(也称为PyStrings)可用于指定较大的文本。文本应由三位双引号(""")分隔符偏移,放在自己的行上
Scenario:
Given a blog post named "Random" with:
"""
Some Title, Eh?
===============
Here is the first paragraph of my blog post.
Lorem ipsum dolor sit amet, consectetur adipiscing
elit.
"""
在您的步骤定义中匹配PyStrings
在您的步骤定义中,无需找到此文本并将其与模式匹配。文本将自动作为最后一个参数传递到步骤定义方法中。例如:
<?php
use Behat\Gherkin\Node\PyStringNode;
// ...
/**
* @When a blog post named :title with:
*/
public function blogPost($title, PyStringNode $markdown)
{
echo 'title='.$title, PHP_EOL,'markdown='.$markdown;
}
PyStrings存储在 PyStringNode 实例中,您可以使用(string) $pystring或$ pystring-> getRaw() 直接转换为一个字符串, 如上例所示。
(注意:后面的多行字符串用的是 with: 来获取,参数会传入 PyStringNode $markdown)
执行结果:
[behat]$ vendor/bin/behat features/default/pystrings.feature
Feature: pystring
Scenario: pystring # features/default/pystrings.feature:2
Given a blog post named "Random" with: # FeatureContext::blogPost()
"""
Some Title, Eh?
===============
Here is the first paragraph of my blog post.
Lorem ipsum dolor sit amet, consectetur adipiscing
elit.
"""
│ title=Random
│ markdown=Some Title, Eh?
│ ===============
│ Here is the first paragraph of my blog post.
│ Lorem ipsum dolor sit amet, consectetur adipiscing
│ elit.
1 scenario (1 passed)
1 step (1 passed)
0m0.03s (13.11Mb)
九、tags [在 *.feature 里面使用的标签]
标签可以分别到 Scenario 和 Scenario Outline;
十、behat.xml
配置格式例子,注意缩进(需要4个空格,很重要):
1)配置格式例子
# behat.yml
default:
suites:
default:
contexts:
- MyAwesomeContext
- MyWickedContext
suite_a:
contexts:
- MyAwesomeContext
- MyWickedContext
suite_b:
contexts: [MyAwesomeContext]
2)支持上下文类(context classes)的初始化参数传递:
<?php
use Behat\Behat\Context\Context;
class MyAwesomeContext implements Context
{
public function __construct($baseUrl, $tempPath)
{
$this->baseUrl = $baseUrl;
$this->tempPath = $tempPath;
}
}
以下配置,需要注意参数的顺序:
#behat.yml
default:
suites:
default:
contexts:
- MyAwesomeContext:
- http://localhost:8080 #初始化第一个参数,将当做 $baseUrl 参数传入
- /var/tmp #初始化第二个参数,将当做 $tempPath 参数传入
3)还可以按变量名设置初始化参数,确保可以取到对应的参数,不用担心顺序问题:
#behat.yml
default:
suites:
default:
contexts:
- MyAwesomeContext:
tempPath: /var/tmp #将当做 $tempPath 参数传入
baseUrl: http://localhost:8080 #将当做 $baseUrl 参数传入
4)如果你的上下文构造函数参数是可选的,配置后,将会覆盖,而不是读取取默认值:
<?php
//......
public function __construct($baseUrl = 'http://localhost', $tempPath = '/var/tmp')
{
$this->baseUrl = $baseUrl;
$this->tempPath = $tempPath;
}
# behat.yml
default:
suites:
default:
contexts:
- MyAwesomeContext:
tempPath: /var/tmp #将替换 $tempPath 的默认值
十一、使用 php 5.4+ 的trait 特性,提高代码复用性。
<?php
trait ProductsDictionary
{
/**
* @Given there is a(n) :product, which costs £:price
*/
public function thereIsAWhichCostsPs($product, $price)
{
throw new PendingException();
}
}
?>
<?php
use Behat\Behat\Context\Context;
class MyAwesomeContext implements Context
{
use ProductsDictionary;
}
?>