Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 24 additions & 27 deletions quick_start.rst
Original file line number Diff line number Diff line change
Expand Up @@ -455,49 +455,46 @@ code we could come up with to fulfil our scenario. Something like this:
#[Then('I should have :arg1 product(s) in the basket')]
public function iShouldHaveProductInTheBasket($count)
{
// Normally you would import this class - we are using the fully qualified name
// to highlight that Behat does not come with an assertion tool (see note below).
\PHPUnit\Framework\Assert::assertCount(
intval($count),
$this->basket
);
if (count($this->basket) !== intval($count)) {
throw new \Exception(
sprintf(
'The basket should have %d item(s), but it has %d.',
intval($count),
count($this->basket)
)
);
}
}

#[Then('the overall basket price should be £:arg1')]
public function theOverallBasketPriceShouldBePs($price)
{
\PHPUnit\Framework\Assert::assertSame(
floatval($price),
$this->basket->getTotalPrice()
);
$expectedPrice = floatval($price);
$actualPrice = $this->basket->getTotalPrice();

if ($expectedPrice !== $actualPrice) {
throw new \Exception(
sprintf(
'Expected basket total price to be %s, but got %s.',
$expectedPrice,
$actualPrice
)
);
}
}
}

As you can see, in order to test and implement our application, we introduced 2 objects -
``Shelf`` and ``Basket``. The first is responsible for storing products and their prices,
the second is responsible for the representation of our customer basket. Through appropriate step
definitions we declare products' prices and add products to the basket. We then compare the
state of our ``Basket`` object with our expectations using PHPUnit assertions.
state of our ``Basket`` object with our expectations and throw exception if the expectations aren't met.

.. note::

Behat doesn't come with its own assertion tool, but you can use any proper assertion
tool out there. A proper assertion tool is a library whose assertions throw
exceptions on failure. For example, if you're familiar with PHPUnit you can use
its assertions in Behat by installing it via composer:

.. code-block:: bash

$ php composer.phar require --dev phpunit/phpunit

and then by simply using assertions in your steps:

.. code-block:: php

\PHPUnit\Framework\Assert::assertCount(
intval($count),
$this->basket
);
tool out there.
Learn more in the paragraph :ref:`assertion-tools`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest more like:

Suggested change
Learn more in the paragraph :ref:`assertion-tools`
Learn more about :ref:`assertion-tools`.


Now try to execute your feature tests:

Expand Down
52 changes: 52 additions & 0 deletions useful_resources.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,58 @@ Integrating Behat with PHPStorm
More information on integrating Behat with PHPStorm can be found in this
`blog post`_.

.. _assertion-tools:

Assertion tools
---------------

A proper assertion tool is a library whose assertions throw exceptions on failure.

For example a list of the most known:

- https://github.com/webmozarts/assert
- https://github.com/beberlei/assert
- https://github.com/zenstruck/assert

.. caution::
If you are familiar with PHPUnit, you can use its assertion library

.. code-block:: bash

$ php composer.phar require --dev phpunit/phpunit

and then by simply using assertions in your steps:

.. code-block:: php

\PHPUnit\Framework\Assert::assertCount(
intval($count),
$this->basket
);

**However, using PHPUnit for assertions no longer works with PHP 11.3.0 and later**.

This is due to a change in how PHPUnit's internal components are initialized.
A direct alternative that provides a complete object and array comparison is not readily available.

Learn more at https://github.com/Behat/Behat/issues/1618.

However, a workaround exists by modifying the PHPUnit bootstrap file (in Symfony is usually at `tests/bootstrap.php`)
to explicitly initialize the PHPUnit configuration when running Behat.
This involves adding the following lines to your bootstrap file:

.. code-block:: php

if (defined('BEHAT_BIN_PATH')) {
(new \PHPUnit\TextUI\Configuration\Builder())->build([]);
}
Comment on lines +57 to +65
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest instead describing / showing an example doing this in a BeforeSuite hook e.g. more like:

use Behat\Hook\BeforeSuite;

class FeatureContext {

    #[BeforeSuite]
    public static function initPhpunit() {
        // If you have multiple suites, you may want to use a static variable to ensure this only runs once.
        (new \PHPUnit\TextUI\Configuration\Builder())->build([]);
    }
}

That has a few advantages:

  • It is guaranteed to work in the same place in any Behat project (e.g. doesn't depend on the path to a bootstrap file).
  • It doesn't depend on the BEHAT_BIN_PATH const which is arguably not part of our public API - I wouldn't expect it to change, but if it did it would be hard to understand what had broken.
  • It inits phpunit much later, nearer the point it might actually be required. So for example if you're running other behat commands or things like --dry-run you won't have the overhead of phpunit booting for no reason.


This is a hack that forces PHPUnit to load the necessary components.
The downside is that it creates a tight coupling between your project and PHPUnit's internal non-public API
and it forces the entire PHPUnit framework to be bootstrapped along with Behat, which results in a larger memory footprint.
This makes the workaround brittle and prone to breaking with future updates.


Behat cheat sheet
-----------------

Expand Down
Loading