SymfonyExtension for Behat

repository·master·Indexed 19 days ago

https://github.com/friendsofbehat/symfonyextension

A Behat extension that integrates Symfony (v6 and v7) applications with Behat testing. It allows developers to define Behat contexts as Symfony services, leveraging autowiring and autoconfiguration to test applications directly without a running web server. The extension provides deep integration with the Mink driver and manages separate containers for contexts and drivers to ensure isolated testing environments.

Tokens
3.9K
Snippets
9
Records
16
Agent score
66%

What's inside SymfonyExtension

  1. Overview of SymfonyExtension

    master

    SymfonyExtension is a Behat extension that provides deep integration with Symfony (^6.0 and ^7.0) and the Mink driver for Symfony applications. It enables a more seamless testing experience by allowing you to:

    • Define your Behat contexts as regular Symfony services.
    • Leverage Symfony's autowiring and autoconfiguring capabilities for your contexts.
    • Test your Symfony application directly without the need to set up a web server.
  2. How Contexts and the Mink Driver work with Symfony Containers

    master

    Unlike the older Behat/Symfony2Extension, this extension treats Behat Contexts as services within your Symfony container. This enables autowiring and autoconfiguration for your contexts.

    To support isolated testing, the extension manages two separate Symfony kernels and containers:

    1. The Context Container: Used to instantiate and autowire your Context classes. You can access this container in your contexts using the @service_container service.
    2. The Driver Container: Used by the symfony Mink driver to handle application requests. This ensures every request is run in a clean, isolated environment, similar to a real web server.

    Accessing the Driver Container

    You can inject the driver's container into your contexts to inspect state (e.g., querying the Symfony Profiler) or to mock/prepare services before a request. To do this, inject the behat.driver.service_container service or type-hint \Symfony\Component\DependencyInjection\ContainerInterface $driverContainer.

    Important Lifecycle Rules

    • Reboots: Both kernels and containers are shut down and rebooted after every scenario (or scenario outline example) to ensure isolation.
    • Resetting: When making multiple Mink requests in one scenario, the driver container is reset before the second and subsequent requests. To ensure you are working with the current state, always call ContainerInterface::get() (or related methods) after a request.
    • Constructor Warning: Do not fetch services from the driver's container inside your context's __construct method. The driver container may not be fully initialized at that stage. Instead, access services within step definitions, @BeforeStep, or @BeforeScenario hooks.
    // Example: Injecting the driver container into a context
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Behat\Behat\Context\Context;
    
    class MyContext implements Context
    {
        private $driverContainer;
    
        public function __construct(ContainerInterface $driverContainer)
        {
            // WARNING: Do not use $driverContainer to fetch services here!
            $this->driverContainer = $driverContainer;
        }
    
        /**
         * @Given I check the profiler
         */
        public function iCheckTheProfiler()
        {
            // Safe to use here
            $profiler = $this->driverContainer->get('profiler');
        }
    }
  3. Integrate Mink with SymfonyExtension

    master

    The extension provides an isolated driver for testing Symfony applications via Mink.

    Installation

    1. Install the required forks of Mink and the BrowserKit driver:
    composer require --dev behat/mink friends-of-behat/mink-extension behat/mink-browserkit-driver
    1. Enable the symfony session in your behat.yaml:
    default:
        extensions:
            Behat\MinkExtension:
                sessions:
                    symfony:
                        symfony: ~

    Usage

    Inject the Behat\Mink\Session into your context constructor.

    Warning: Calling any method on Mink-related services directly inside the constructor is not permitted and will cause errors. You must use the injected session instance within your step definitions.

  4. Install the SymfonyExtension for Symfony 3

    master

    For legacy Symfony 3 projects:

    1. Install via Composer:
    composer require --dev friends-of-behat/symfony-extension:^2.0
    1. Enable the extension in behat.yml or behat.yml.dist:
    default:
        extensions:
            FriendsOfBehat\SymfonyExtension: ~
    1. Register the bundle in app/AppKernel.php:
    public function registerBundles()
    {
        $bundles = array(/* ... */);
        
        if ('test' === $this->getEnvironment()) {
            $bundles[] = new \FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle();
        }
    }
    1. Create the Behat directory:
    mkdir -p tests/Behat
    1. Configure autowiring in app/config/config_test.yml:
    services:
        _defaults:
            autowire: true
            autoconfigure: true
    
        Tests\Behat\:
            resource: '../../tests/Behat/*'
  5. Configure Symfony for SymfonyExtension 2.0

    master

    To use SymfonyExtension 2.0, you must update your Symfony kernel configuration:

    1. Register the \FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle bundle in your kernel specifically for the test environment.
    2. Ensure your context service definitions are loaded in the test environment.
  6. Install the SymfonyExtension

    master

    To install the extension, use Composer. The recommended method depends on your Symfony version and whether you use Symfony Flex.

    Symfony 6/7 (with Flex)

    Run the following command to install the extension and allow for contrib recipes:

    composer require --dev friends-of-behat/symfony-extension:^2.0

    Symfony 6/7 (without Flex)

    1. Install via Composer:
    composer require --dev friends-of-behat/symfony-extension:^2.0
    1. Enable the extension in your behat.yaml or behat.yaml.dist:
    default:
        extensions:
            FriendsOfBehat\SymfonyExtension: ~
    1. Register the helper bundle in config/bundles.php:
    return [
        // ...
        FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle::class => ['test' => true],
    ];
    1. Create the Behat directory:
    mkdir -p tests/Behat
    1. Configure autowiring for Behat services in config/services_test.yaml:
    services:
        _defaults:
            autowire: true
            autoconfigure: true
    
        App\Tests\Behat\:
            resource: '../tests/Behat/*'

    Symfony 3 (Legacy)

  7. Update Mink dependencies when using SymfonyExtension 2.x

    master

    If your composer.json contains friends-of-behat/mink-browserkit-driver or friends-of-behat/mink, you must replace them with the official Behat versions to ensure compatibility with SymfonyExtension 2.x.

    Remove:

    • friends-of-behat/mink-browserkit-driver
    • friends-of-behat/mink

    Add:

    • behat/mink-browserkit-driver
    • behat/mink
    composer remove friends-of-behat/mink-browserkit-driver friends-of-behat/mink
    composer require behat/mink-browserkit-driver behat/mink
  8. Configure the FriendsOfBehat\SymfonyExtension

    master

    The extension can be configured in your behat.yaml or behat.yaml.dist file. If no configuration is provided, the extension attempts to auto-detect settings based on your Symfony version.

    Configuration Options

    KeyDescription
    bootstrapPath to a file required once during extension loading (e.g., to set env vars). Defaults to config/bootstrap.php (Symfony 4/5) or app/autoload.php (Symfony 3).
    kernel.classFully qualified class name of the application kernel. Defaults to App\Kernel (Symfony 4/5) or AppKernel (Symfony 3).
    kernel.pathPath to the file containing the kernel class. Required if the kernel is not autoloaded by Composer.
    kernel.environmentThe Symfony environment to use. Defaults to the APP_ENV env var or test.
    kernel.debugWhether debug mode is enabled. Defaults to the APP_DEBUG env var or true.
    # behat.yaml.dist / behat.yaml
    
    default:
        extensions:
            FriendsOfBehat\SymfonyExtension:
                bootstrap: ~
                kernel:
                    class: ~
                    path: ~
                    environment: ~
                    debug: ~
  9. Configure Behat Extensions for SymfonyExtension 2.0

    master

    Update your behat.yml configuration to align with the 2.0 API:

    Remove obsolete extensions

    Remove FriendsOfBehat\CrossContainerExtension and FriendsOfBehat\ContextServiceExtension from your extensions list.

    Update SymfonyExtension configuration keys

    • Rename kernel.env to kernel.environment.
    • Move kernel.bootstrap to bootstrap.
    • Note: The env_file setting has been removed. Use your original Symfony bootstrap file or a custom one to load environment variables.
  10. Inject Symfony Parameters into Behat Contexts

    master

    You can inject specific Symfony parameters (like %kernel.environment%) into your Behat context constructors.

    With autowiring enabled, simply type-hint the parameter in the constructor. If autowiring is disabled, register the context as a public service and pass the parameter using the %parameter.name% syntax in your services_test.yaml or config_test.yml.

    final class DemoContext implements Context
    {
        private $environment;
        
        public function __construct(string $environment) 
        {
            $this->environment = $environment;
        }
    
        /** @Then the application's kernel should use :expected environment */
        public function kernelEnvironmentShouldBe(string $expected): void
        {
            if ($this->environment !== $expected) {
                throw new \RuntimeException();
            }
        }
    }