Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accessing tested application services easily via driver's service container #116

Merged
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
Feature: Accessing driver's service container

Background:
Given a working Symfony application with SymfonyExtension configured
And a Behat configuration containing:
"""
default:
extensions:
Behat\MinkExtension:
base_url: "http://localhost:8080/"
default_session: symfony
sessions:
symfony:
symfony: ~
suites:
default:
contexts:
- App\Tests\SomeContext
"""
And a feature file containing:
"""
Feature:
Scenario:
Given the counter service is zeroed
When I visit the page "/hello-world"
Then the counter service should return 1
"""
And a context file "tests/SomeContext.php" containing:
"""
<?php

namespace App\Tests;

use App\Counter;
use Behat\Behat\Context\Context;
use Behat\Mink\Mink;
use Symfony\Component\DependencyInjection\ContainerInterface;

final class SomeContext implements Context {
private $mink;
private $driverContainer;

public function __construct(Mink $mink, ContainerInterface $driverContainer)
{
$this->mink = $mink;
$this->driverContainer = $driverContainer;
}

/** @Given the counter service is zeroed */
public function counterServiceIsZeroed(): void
{
assert(0 === $this->getCounterService()->get());
}

/** @When I visit the page :page */
public function visitPage(string $page): void
{
$this->mink->getSession()->visit($page);
}

/** @Then the counter service should return :number */
public function counterServiceShouldReturn(int $number): void
{
assert($number === $this->getCounterService()->get());
}

private function getCounterService(): Counter
{
return $this->driverContainer->get('App\Counter');
}
}
"""

Scenario: Accessing a service from driver's service container (manually injected dependencies)
Given a YAML services file containing:
"""
services:
App\Tests\SomeContext:
public: true
arguments:
- '@behat.mink'
- '@behat.driver.service_container'
"""
When I run Behat
Then it should pass

Scenario: Accessing a service from driver's service container (autowired & autoconfigured dependencies)
Given a YAML services file containing:
"""
services:
_defaults:
autowire: true
autoconfigure: true

App\Tests\SomeContext: ~
"""
When I run Behat
Then it should pass
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,23 @@
use Behat\Mink\Mink;
use Behat\Mink\Session;
use FriendsOfBehat\SymfonyExtension\Mink\MinkParameters;
use FriendsOfBehat\SymfonyExtension\ServiceContainer\SymfonyExtension;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\HttpKernel\KernelInterface;

final class FriendsOfBehatSymfonyExtensionExtension extends Extension implements CompilerPassInterface
{
public function load(array $configs, ContainerBuilder $container): void
{
$this->provideMinkIntegration($container);
$this->registerBehatContainer($container);
$this->registerDriverBehatContainer($container);

$container->registerForAutoconfiguration(Context::class)->addTag('fob.context');
}
Expand All @@ -47,6 +50,27 @@ private function registerBehatContainer(ContainerBuilder $container): void
$container->setDefinition('behat.service_container', $behatServiceContainerDefinition);
}

private function registerDriverBehatContainer(ContainerBuilder $container): void
{
$driverKernelDefinition = new Definition(KernelInterface::class, [SymfonyExtension::DRIVER_KERNEL_ID]);
$driverKernelDefinition->setFactory([new Reference('behat.service_container'), 'get']);
$driverKernelDefinition->setPublic(true);
$driverKernelDefinition->setLazy(true);

$driverServiceContainerDefinition = new Definition(ContainerInterface::class);
$driverServiceContainerDefinition->setFactory([$driverKernelDefinition, 'getContainer']);
$driverServiceContainerDefinition->setPublic(true);
$driverServiceContainerDefinition->setLazy(true);

$driverTestServiceContainerDefinition = new Definition(ContainerInterface::class, ['test.service_container']);
$driverTestServiceContainerDefinition->setFactory([$driverServiceContainerDefinition, 'get']);
$driverTestServiceContainerDefinition->setPublic(true);
$driverTestServiceContainerDefinition->setLazy(true);

$container->setDefinition('behat.driver.service_container', $driverTestServiceContainerDefinition);
$container->registerAliasForArgument('behat.driver.service_container', ContainerInterface::class, 'driver container');
}

private function provideBrowserKitIntegration(ContainerBuilder $container): void
{
if (!class_exists(Client::class) || !$container->has('test.client')) {
Expand Down
2 changes: 1 addition & 1 deletion src/ServiceContainer/SymfonyExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ final class SymfonyExtension implements Extension
* Kernel used by Symfony driver to isolate web container from contexts' container.
* Container is rebuilt before every request.
*/
private const DRIVER_KERNEL_ID = 'fob_symfony.driver_kernel';
public const DRIVER_KERNEL_ID = 'fob_symfony.driver_kernel';

/** @var bool */
private $minkExtensionFound = false;
Expand Down
77 changes: 69 additions & 8 deletions tests/Behat/Context/TestContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,24 +92,20 @@ class: App\Kernel
$this->thereIsFile('src/Kernel.php', <<<'CON'
<?php

declare(strict_types=1);

namespace App;

use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel as HttpKernel;
use Symfony\Component\Routing\RouteCollectionBuilder;

class Kernel extends HttpKernel
{
use MicroKernelTrait;

public function helloWorld(): Response
{
return new Response('Hello world!');
}

public function registerBundles(): iterable
{
return [
Expand All @@ -125,17 +121,82 @@ protected function configureContainer(ContainerBuilder $container, LoaderInterfa
'secret' => 'Pigeon',
]);

$loader->load(__DIR__ . '/../config/default.yaml');
$loader->load(__DIR__ . '/../config/services.yaml');
}

protected function configureRoutes(RouteCollectionBuilder $routes)
protected function configureRoutes(RouteCollectionBuilder $routes): void
{
$routes->add('/hello-world', 'App\Controller:helloWorld');
}
}
CON
);

$this->thereIsFile('src/Controller.php', <<<'CON'
<?php

declare(strict_types=1);

namespace App;

use Symfony\Component\HttpFoundation\Response;

final class Controller
{
private $counter;

public function __construct(Counter $counter)
{
$this->counter = $counter;
}

public function helloWorld(): Response
{
$this->counter->increase();

return new Response('Hello world!');
}
}
CON
);

$this->thereIsFile('src/Counter.php', <<<'CON'
<?php

declare(strict_types=1);

namespace App;

final class Counter
{
private $counter = 0;

public function increase(): void
{
$routes->add('/hello-world', 'kernel:helloWorld');
$this->counter++;
}

public function get(): int
{
return $this->counter;
}
}
CON
);

$this->thereIsFile('config/default.yaml', <<<'YML'
services:
App\Controller:
arguments:
- '@App\Counter'
public: true

App\Counter:
public: false
YML
);

$this->thereIsFile('config/services.yaml', '');
}

Expand Down