当存在多种情况时,Behat会挂起,但只能在一个情况下工作

abb*_*ood 5 php bdd behat laravel-5 laravel-5.4

我有这样写的Behat测试用例:

Feature: Checkout
In order to buy products
As a customer
I need to be able to checkout items in the cart

Background: 
    Given step 1
    And step 2

@Ready
Scenario: Deliver now
    When step 3
    Then step 4

@NoneReady
Scenario: Deliver later
    When step a
    Then step b
    And step c


@AddressNotCovered
Scenario: Address Not Covered
    When step i
    Then step ii
Run Code Online (Sandbox Code Playgroud)

如果我在单个标签上运行behat,它就可以正常工作:

$ behat --tags=Ready
Feature: Checkout
  In order to buy products
  As a customer
  I need to be able to checkout items in the cart

  @Ready
  Scenario: Deliver now                                                                 # tests/features/Checkout/CheckOut.feature:9
    step 1
    And step 2 
    .. 

1 scenario (1 passed)
7 steps (7 passed)
0m3.85s (36.62Mb)
Run Code Online (Sandbox Code Playgroud)

但是,如果我在多个标签上运行它,它将挂在第一个标签的末尾:

behat --tags=Ready,AddressNotCovered
Feature: Checkout
  In order to buy products
  As a customer
  I need to be able to checkout items in the cart

  @Ready
  Scenario: Deliver now                                                                 # tests/features/Checkout/CheckOut.feature:9
    Given step ..
    ..
    And .. 

    // hangs here
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

环境

Laravel 5.4
Behat 3.1.0
PHP 7.1.23
PHPUnit 5.7.27
Run Code Online (Sandbox Code Playgroud)

从我的composer.json

"require": {
    "php": ">=5.5.9",
    "laravel/framework": "5.4.*",
    ..
    "behat/behat": "3.1.0",
    "laracasts/behat-laravel-extension": "^1.1",
},
"require-dev": {
    "phpunit/phpunit": "~5.7",
    "phpspec/phpspec": "~2.1",
    "johnkary/phpunit-speedtrap": "^1.0",
},
Run Code Online (Sandbox Code Playgroud)

Behat.yml

default:
  extensions:
      Laracasts\Behat:
          env_path: .env.testing
  autoload:
    - ./tests/features/bootstrap
  suites:

    Checkout:
      paths: [./tests/features/Checkout]
      contexts: [CheckoutFeatureContext]
Run Code Online (Sandbox Code Playgroud)

更新资料

我试图创建示例小黄瓜来说明上述问题。尝试自动添加摘要时遇到了相同的问题。追加片段适用于单个方案,但在多个方案中失败:

工作示例:单一场景

# tests/features/Example/Example.feature

Feature: Example
In order to show dev team how to use behat/gherkin using background 
As a developer
I need to be able write gherkin using a background and multiple scenarios 
And all scenarios should run 

Background: 
    Givens setup condition 1 
    And setup condition 2 


Scenario: scenario one 
    When I perform first sample trigger point 
    Then result one must happen 
    And result two must happen 
Run Code Online (Sandbox Code Playgroud)

当我运行以下命令

behat tests/features/Example/Example.feature  --append-snippets
Run Code Online (Sandbox Code Playgroud)

添加代码片段效果很好

Feature: Example
  In order to show dev team how to use behat/gherkin using background
  As a developer
  I need to be able write gherkin using a background and multiple scenarios
  And all scenarios should run

  Background:             # tests/features/Example/Example.feature:9
      Givens setup condition 1
    And setup condition 2

  Scenario: scenario one                      # tests/features/Example/Example.feature:13
    When I perform first sample trigger point
    Then result one must happen
    And result two must happen

1 scenario (1 undefined)
4 steps (4 undefined)
0m0.48s (24.63Mb)

u tests/features/bootstrap/FeatureContext.php - `setup condition 2` definition added
u tests/features/bootstrap/FeatureContext.php - `I perform first sample trigger point` definition added
u tests/features/bootstrap/FeatureContext.php - `result one must happen` definition added
u tests/features/bootstrap/FeatureContext.php - `result two must happen` definition added
Run Code Online (Sandbox Code Playgroud)

失败的示例:多种情况

当我们有多种情况时

# tests/features/Example/Example.feature

Feature: Example
In order to show dev team how to use behat/gherkin using background 
As a developer
I need to be able write gherkin using a background and multiple scenarios 
And all scenarios should run 

Background: 
    Givens setup condition 1 
    And setup condition 2 

Scenario: scenario one 
    When I perform first sample trigger point 
    Then result one must happen 
    And result two must happen 

Scenario: scenario two 
    When I perform second sample trigger point 
    Then result a must happen 
    And result b must happen 
Run Code Online (Sandbox Code Playgroud)

运行相同的--append-snippets命令扼流圈:

Feature: Example
  In order to show dev team how to use behat/gherkin using background
  As a developer
  I need to be able write gherkin using a background and multiple scenarios
  And all scenarios should run

  Background:             # tests/features/Example/Example.feature:9
      Givens setup condition 1
    And setup condition 2

  Scenario: scenario one                      # tests/features/Example/Example.feature:13
    When I perform first sample trigger point
    Then result one must happen
    And result two must happen

^C // had to abort here
Run Code Online (Sandbox Code Playgroud)

abb*_*ood 3

事实证明,上面的例子太简单了。做了一些研究后(这篇文章特别有帮助特别有帮助),我意识到这种“停滞”是由于每次测试后拆除数据库造成的。这就是修复它的原因:

\n\n

首先我替换DatabaseTransactionsDatabaseMigrations在我的 FeatureContext 类中

\n\n
class FeatureContext extends TestCase implements  Context, SnippetAcceptingContext\n{\n\n    use DatabaseMigrations, ..\n
Run Code Online (Sandbox Code Playgroud)\n\n

鉴于上述情况,我从我的 bitbucket 管道脚本中删除了手动迁移命令

\n\n
- php artisan --env=testing config:cache\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是有道理的,因为使用新代码,数据库将始终在每次测试之前刷新和迁移。

\n\n

然后我将调用添加setUp()behat 挂钩:

\n\n
/** @BeforeScenario */\npublic function before(BeforeScenarioScope $scope)\n{\n    parent::setUp();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

就是这样。该解决方案最好的部分是它使我的本地测试环境与 bitbucket 管道的测试环境完全一致,因此结果始终相同。

\n\n

进一步解释:来自我们的维基

\n\n

一般来说,最好重新开始每个测试,而不要保留上一个测试的剩余内容(尤其是在数据库方面)。用 Laravel 的话来说:

\n\n
\n

每次测试后重置数据库通常很有用,这样来自先前测试的数据就不会干扰后续测试。

\n
\n\n

为此,我们使用迁移。话虽如此,由于我们实际上使用的是 Behat,因此我们需要在每个场景生命周期之前和之后进行此迁移。我们使用Behat 的钩子来做到这一点. We do that here:

\n\n
/** @BeforeScenario */\n    public function before(BeforeScenarioScope $scope)\n    {\n        parent::setUp();\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

parent::setUP()讲述Laravel 框架在每个场景之前和之后执行必要的工作:

\n\n
 protected function setUp()\n    {\n        if (! $this->app) {\n            $this->refreshApplication();\n        }\n        $this->setUpTraits(); <---- here\n        ..\n
Run Code Online (Sandbox Code Playgroud)\n\n

这又调用设置特征:

\n\n
   protected function setUpTraits()\n    {\n        $uses = array_flip(class_uses_recursive(static::class));\n        if (isset($uses[DatabaseMigrations::class])) {\n            $this->runDatabaseMigrations();\n        }\n        ..\n
Run Code Online (Sandbox Code Playgroud)\n\n

这称为

\n\n
public function runDatabaseMigrations()\n{\n    $this->artisan(\'migrate:fresh\');\n    $this->app[Kernel::class]->setArtisan(null);\n    $this->beforeApplicationDestroyed(function () {\n        $this->artisan(\'migrate:rollback\');\n        RefreshDatabaseState::$migrated = false;\n    });\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,一旦应用程序被销毁,Laravel 也会回滚更改。了解这一点非常重要,这样可以防止 Behat 在存在多个场景且给定的情况下停滞不前。还要记住,当我们像这样使用小黄瓜时:

\n\n
Feature: Checkout\nIn order to buy products\nAs a customer\nI need to be able to checkout items in the cart\n\nBackground: \n    Given step 1\n    And step 2\n\n@Ready\nScenario: Deliver now\n    When step 3\n    Then step 4\n\n@NoneReady\nScenario: Deliver later\n    When step a\n    Then step b\n    And step c\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后每个场景都以后台步骤开始,\xc2\xa0不在场景步骤本身中

\n\n

例子:

\n\n
Feature: Checkout\nIn order to buy products\nAs a customer\nI need to be able to checkout items in the cart\n\nBackground:\n    Given step 1  <-- every scenario starts here, so we call setup before this step\n    And step 2\n\n@Ready\nScenario: Deliver now\n    When step 3 <-- not here\n    Then step 4\n\n@NoneReady\nScenario: Deliver later\n    When step a\n    Then step b\n    And step c\n
Run Code Online (Sandbox Code Playgroud)\n