Skip to content

[Testing] Create a section dedicated to sending multiple requests in one functional test #18789

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

Merged
merged 1 commit into from
Sep 11, 2023
Merged
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
59 changes: 51 additions & 8 deletions testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -619,15 +619,58 @@ This allows you to create all types of requests you can think of:
:ref:`framework.test <reference-framework-test>` option is enabled).
This means you can override the service entirely if you need to.

.. caution::
Multiple Requests in One Test
.............................

After you send one request, subsequent ones will make the client reboot
the kernel, recreating the container from scratch.
This ensures that requests are "isolated" using "new" service objects.
However, this can cause some unexpected behaviors. For example, the
security token will be cleared, Doctrine entities will be "detached"…

Calling the client's
:method:`Symfony\\Bundle\\FrameworkBundle\\KernelBrowser::disableReboot`
method is the first step to work around this, as this will reset the kernel
instead of rebooting it. Now, resetting the kernel will call the ``reset()``
method of every ``kernel.reset`` tagged service, which will **also** clear
the security token, detach entities and so on.

As such, the next step is to create a
:doc:`compiler pass </service_container/compiler_passes>` to remove the
``kernel.reset`` tag from these services in your test environment::

// src/Kernel.php
namespace App;

use App\DependencyInjection\Compiler\CustomPass;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;

class Kernel extends BaseKernel
{
use MicroKernelTrait;

// …

Before each request, the client reboots the kernel, recreating
the container from scratch.
This ensures that every requests are "isolated" using "new" service objects.
Also, it means that entities loaded by Doctrine repositories will
be "detached", so they will need to be refreshed by the manager or
queried again from a repository.
You can disable this behavior by calling the :method:`disableReboot() <Symfony\\Bundle\\FrameworkBundle\\KernelBrowser::disableReboot>` method.
protected function build(ContainerBuilder $container): void
{
if ('test' === $this->environment) {
$container->addCompilerPass(new class() implements CompilerPassInterface {
public function process(ContainerBuilder $container): void
{
// prevents the security token to be cleared
$container->getDefinition('security.token_storage')->clearTag('kernel.reset');

// prevents entities to be detached
$container->getDefinition('doctrine')->clearTag('kernel.reset');

// …
}
});
}
}
}

Browsing the Site
.................
Expand Down