Behat hangs when there are multiple scenarios, but works on a single one

懵懂的女人 提交于 2019-12-10 14:10:20

问题


I have Behat test cases written like so:

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

If I run behat on a single tag, it works just fine:

$ 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)

But if I run it on multiple tags, it hangs at the end of the first tag:

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

What am I doing wrong?

Environment

Laravel 5.4
Behat 3.1.0
PHP 7.1.23
PHPUnit 5.7.27

from my 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",
},

Behat.yml

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

    Checkout:
      paths: [./tests/features/Checkout]
      contexts: [CheckoutFeatureContext]

Update

I tried to create sample gherkin to illustrate the problem above. I ran into the same problem when trying to auto append snippets. Appending snippets worked with a single scenario, but failed on multiple scenarios:

working example: single scenario

# 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 

When I run the following command

behat tests/features/Example/Example.feature  --append-snippets

adding snippets worked just fine

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

failing example: multiple scenarios

when we have multiple scenarios

# 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 

running the same --append-snippets command chokes:

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

回答1:


It turns out the examples above were too simplistic. After doing some research (especially helpful was this post) I realized that this "stalling" is due to tearing down the database after each test. So this is what fixed it:

First I replaced DatabaseTransactions with DatabaseMigrations in my FeatureContext class:

class FeatureContext extends TestCase implements  Context, SnippetAcceptingContext
{

    use DatabaseMigrations, ..

Given the above, I removed the manual migration comand from my bitbucket pipeline script

- php artisan --env=testing config:cache

which makes sense since with the new code, the database will always be refreshed and migrated before each test.

Then I added the setUp() call to the behat hooks:

/** @BeforeScenario */
public function before(BeforeScenarioScope $scope)
{
    parent::setUp();
}

And that's it. The best part about this solution is that it completely aligned my local testing environment with that of bitbucket pipelines, so that the results were always the same.

Further explanation: from our wiki

In general, it's a good idea to start each test fresh without left overs from the previous test (esp when it comes to databases). In the words of laravel:

It is often useful to reset your database after each test so that data from a previous test does not interfere with subsequent tests.

For that we use migrations. That being said, since we're actually using Behat, we need this migration to happen before and after each scenario life cycle. We do that using Behat's hooks. We do that here:

/** @BeforeScenario */
    public function before(BeforeScenarioScope $scope)
    {
        parent::setUp();
    }

parent::setUP() tells the Laravel framework to do the necessary work before and after each scenario:

 protected function setUp()
    {
        if (! $this->app) {
            $this->refreshApplication();
        }
        $this->setUpTraits(); <---- here
        ..

This in turn calls setup traits:

   protected function setUpTraits()
    {
        $uses = array_flip(class_uses_recursive(static::class));
        if (isset($uses[DatabaseMigrations::class])) {
            $this->runDatabaseMigrations();
        }
        ..

which calls this

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

Notice that Laravel will also rollback the changes once the application is destroyed. It's very important to understand this in order to prevent Behat stalling when there are multiple scenarios and a given before them. Also keep in mind that when we use Gherkin like so:

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

Then each scenario starts with the background steps, not in the scenario steps itself

Example:

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  <-- every scenario starts here, so we call setup before this step
    And step 2

@Ready
Scenario: Deliver now
    When step 3 <-- not here
    Then step 4

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



回答2:


The following steps work for me on Arch Linux and PHP 7.3:

composer global require laravel/installer
laravel new behat-laravel
cd behat-laravel
composer require behat/behat behat/mink behat/mink-extension laracasts/behat-laravel-extension --dev
touch behat.yml
# edit behat.yml
# edit features/bootstrap/FeatureContext.php
vendor/bin/behat --init
# Add steps and tag them
vendor/bin/behat
vendor/bin/behat --tags Ready,NoneReady
# behat.yml
default:
    extensions:
        Laracasts\Behat:
            # env_path: .env.behat
        Behat\MinkExtension:
            default_session: laravel
            laravel: ~
<?php
// features/bootstrap/FeatureContext.php

use Behat\Behat\Hook\Scope\AfterStepScope;
use Behat\Behat\Tester\Exception\PendingException;
use Behat\Behat\Context\Context;
use Behat\Behat\Context\SnippetAcceptingContext;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
#This will be needed if you require "behat/mink-selenium2-driver"
#use Behat\Mink\Driver\Selenium2Driver;
use Behat\MinkExtension\Context\MinkContext;

/**
 * Defines application features from the specific context.
 */
class FeatureContext extends MinkContext implements Context, SnippetAcceptingContext
{
    /**
     * Initializes context.
     *
     * Every scenario gets its own context instance.
     * You can also pass arbitrary arguments to the
     * context constructor through behat.yml.
     */
    public function __construct()
    {
    }

    /**
     * @When stepready :arg1
     */
    public function stepready($arg1)
    {
        return true;
    }

    /**
     * @When steplater :arg1
     */
    public function steplater($arg1)
    {
        return true;
    }

}
# feature/customer.feature
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 
    When stepready 1
    Then stepready 2 

  @NoneReady
  Scenario: Deliver later
    When steplater 1
    Then steplater 2 
frosch ➜ behat-laravel vendor/bin/behat --tags Ready,NoneReady
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 # features/customer.feature:7
    When stepready 1    # FeatureContext::stepready()
    Then stepready 2    # FeatureContext::stepready()

  @NoneReady
  Scenario: Deliver later # features/customer.feature:12
    When steplater 1      # FeatureContext::steplater()
    Then steplater 2      # FeatureContext::steplater()

2 Szenarien (2 bestanden)
4 Schritte (4 bestanden)
0m0.02s (18.47Mb)


来源:https://stackoverflow.com/questions/57409623/behat-hangs-when-there-are-multiple-scenarios-but-works-on-a-single-one

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!