Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
14a3fba
doc: document `printSkippedSteps` formatter option (#211)
carlos-granados Dec 11, 2025
d44c545
chore(deps): bump urllib3 from 2.5.0 to 2.6.0 (#210)
dependabot[bot] Dec 11, 2025
c396a2c
update to tell PHPUnit assertions stopped working (#208)
loru88 Jan 8, 2026
962ac3c
chore(deps): bump urllib3 from 2.6.0 to 2.6.3 (#212)
dependabot[bot] Jan 12, 2026
9542d3b
chore(deps): bump wheel from 0.44.0 to 0.46.2 (#215)
dependabot[bot] Feb 2, 2026
ce79141
docs: fix the PHPUnit caution block (#214)
loru88 Feb 16, 2026
29e9e41
docs: Behat and AI (#216)
carlos-granados Feb 17, 2026
e551797
Fix the github URL for the "Edit on GitHub" button
stof Mar 6, 2026
478d99d
Merge pull request #218 from Behat/stof-patch-1
stof Mar 6, 2026
9350739
docs: document Gherkin parser compatibility mode (#219)
acoulton Mar 26, 2026
9b06d14
chore(deps): bump requests from 2.32.4 to 2.33.0 (#220)
dependabot[bot] Mar 27, 2026
0400051
chore(deps): bump pygments from 2.18.0 to 2.20.0 (#221)
dependabot[bot] Mar 31, 2026
a6f5590
chore(deps): bump urllib3 from 2.6.3 to 2.7.0 (#222)
dependabot[bot] May 17, 2026
9a230c4
chore(deps): bump idna from 3.10 to 3.15 (#223)
dependabot[bot] May 20, 2026
b767699
Fixed incorrect "OR" tag specified for tagged hooks
jdevinemt May 27, 2026
e5f2df4
Merge pull request #224 from jdevinemt/patch-1
stof May 27, 2026
5a362ed
chore(deps): bump starlette from 0.49.1 to 1.0.1 (#225)
dependabot[bot] Jun 8, 2026
f5a640e
chore(deps): bump starlette from 1.0.1 to 1.3.1 (#226)
dependabot[bot] Jun 18, 2026
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
84 changes: 84 additions & 0 deletions behat_and_ai.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
Behat and AI
============

AI coding agents can generate and modify code based on behavioural descriptions.
Behat provides a reliable way to define, verify, and preserve behaviour in these workflows.

By expressing behaviour as executable scenarios, Behat ensures that AI-generated code
satisfies a clear and objective contract.

Using Behat as a Behavioural Contract
-------------------------------------

Behat scenarios define observable behaviour in a precise and executable form:

.. code-block:: gherkin

Feature: Refund processing

Scenario: Refunding a paid order
Given there is a paid order
When I refund the order
Then the order should be marked as refunded

Scenario: Prevent duplicate refunds
Given an order has already been refunded
When I refund the order
Then the refund should be rejected

AI agents can implement features and use Behat to verify that the expected behaviour is satisfied.
When scenarios pass, the behavioural contract is fulfilled.

Executable and Verifiable Behaviour
-----------------------------------

Behat scenarios serve as executable specifications. They can be used by AI agents to:

* verify correctness after implementing a feature
* detect behavioural regressions
* ensure behaviour remains consistent during refactoring

Because scenarios are executable, they remain accurate as the system evolves.

Generating Scenarios with AI
----------------------------

AI agents can generate Behat scenarios from behavioural descriptions.
These scenarios can then be reviewed, refined, and executed.

This allows behaviour to be defined before or alongside implementation.

Behat provides a structured and executable representation of behaviour
that can be used directly by AI tooling.

Human Review and Iteration
--------------------------

As with any specification or testing tool, generated scenarios and assertions should be reviewed carefully.
It is critical to ensure that both the human-readable scenarios and the executable step definitions
accurately represent the intended behaviour. They also need to be robust enough to prove that
the actual behaviour matches the expectations, even if the implementation changes.

Once validated, scenarios serve as the authoritative definition of the feature. AI agents can implement
or modify the system until all scenarios pass.

This creates a reliable feedback loop where behaviour is defined, verified, and preserved.

Maintaining Behaviour Over Time
-------------------------------

With well-designed scenarios and step definitions, Behat ensures that behaviour remains stable as code changes.
AI agents can safely modify or refactor code, and Behat will detect any unintended behavioural changes.

As long as scenarios pass, the defined behaviour is preserved.

Behat MCP Server
----------------

Behat provides an `MCP (Model Context Protocol) server`_ that allows AI agents to interact
directly with Behat projects.

The MCP server enables agents to discover scenarios, execute Behat,
and integrate behavioural verification into automated workflows.

.. _`MCP (Model Context Protocol) server`: https://github.com/Behat/mcp-server
2 changes: 1 addition & 1 deletion conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
logo_height = 50,

# Base path for "Edit on GitHub" links
github_url="https://github.com/Behat/docs/blob/v3.0/",
github_url="https://github.com/Behat/docs/blob/v3.x/",

# Global header / footer links as text|target
header_links=', '.join([
Expand Down
1 change: 1 addition & 0 deletions index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ and many more.
cookbooks
releases
useful_resources
behat_and_ai
community

.. _`Behaviour Driven Development`: https://en.wikipedia.org/wiki/Behavior-driven_development
Expand Down
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 about :ref:`assertion-tools`.

Now try to execute your feature tests:

Expand Down
12 changes: 6 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ click==8.1.8
colorama==0.4.6
docutils==0.21.2
h11==0.16.0
idna==3.10
idna==3.15
imagesize==1.4.1
Jinja2==3.1.6
MarkupSafe==3.0.2
packaging==24.1
Pygments==2.18.0
requests==2.32.4
Pygments==2.20.0
requests==2.33.0
setuptools==78.1.1
sniffio==1.3.1
snowballstemmer==2.2.0
Expand All @@ -28,10 +28,10 @@ sphinxcontrib-htmlhelp==2.1.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==2.0.0
sphinxcontrib-serializinghtml==2.0.0
starlette==0.49.1
starlette==1.3.1
typing_extensions==4.13.1
urllib3==2.5.0
urllib3==2.7.0
uvicorn==0.34.0
watchfiles==1.0.4
websockets==15.0.1
wheel==0.44.0
wheel==0.46.2
54 changes: 54 additions & 0 deletions useful_resources.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,60 @@ 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

.. admonition:: Caution with PHPUnit
:class: 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
);

**WARNING: using PHPUnit for assertions no longer works with PHP 11.3.0 and later out-of-the-box**.

This is due to a change in how PHPUnit's internal components are initialized. The recommended workaround
to use the PHPUnit assertions is to bootstrap PHPUnit during Behat execution from a ``BeforeSuite`` hook:

.. code-block:: php

use Behat\Hook\BeforeSuite;

class FeatureContext {

#[BeforeSuite]
public static function initPhpunit() {
(new \PHPUnit\TextUI\Configuration\Builder())->build([]);
}
}

If you have multiple suites, you may want to use a static variable in the hook to ensure the initialization only
runs once.

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


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

Expand Down
2 changes: 2 additions & 0 deletions user_guide/command_line_tool/formatting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ The following options are specific to the Pretty formatter:
``ShowOutputOption`` enum values, defaults to ``ShowOutputOption::Yes``.
* ``shortSummary`` show just a list of failing scenarios at the end of the output. If false, a full summary
(which also includes a list of failing steps) will be printed. Defaults to true
* ``printSkippedSteps`` If the output should include any steps which are skipped by the runner. Useful when you
don't want to see all the skipped steps after a failed step. Defaults to true

Progress formatter
^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 3 additions & 1 deletion user_guide/context/hooks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,9 @@ Tagged Hooks
Sometimes you may want a certain hook to run only for certain scenarios,
features or steps. This can be achieved by associating a ``BeforeFeature``,
``AfterFeature``, ``BeforeScenario`` or ``AfterScenario`` hook with one
or more tags. You can also use ``OR`` (``||``) and ``AND`` (``&&``) tags:
or more tags. You can also use ``OR`` (``,``) and ``AND`` (``&&``) tags:

Use the ``,`` tag to execute a hook when it has *any* of the provided tags:

.. code-block:: php

Expand Down
12 changes: 12 additions & 0 deletions user_guide/gherkin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ real, human language telling you what code you should write.
If you're still new to Behat, jump into the :doc:`/quick_start` first,
then return here to learn more about Gherkin.

.. note::

You can configure whether Behat's Gherkin parsing is compatible with
previous Behat versions, or with the official ``cucumber/gherkin``
parsers. See :doc:`gherkin/parser_mode` for more details.

Gherkin Syntax
--------------

Expand Down Expand Up @@ -103,3 +109,9 @@ run:
Behat the ability to have multilanguage features in one suite.

.. _`Business Readable, Domain Specific Language`: http://martinfowler.com/bliki/BusinessReadableDSL.html

.. toctree::
:maxdepth: 2
:hidden:

gherkin/parser_mode
Loading
Loading