liip / LiipTestFixturesBundle

This bundles enables efficient loading of Doctrine fixtures in functional test-cases for Symfony applications
https://liip.ch
MIT License
167 stars 45 forks source link

The kernel should only be booted once #128

Closed quentint closed 3 years ago

quentint commented 3 years ago

Preconditions

  1. On a Symfony 5.3 app
  2. Using ^2.0.0-alpha4
  3. Following these docs: https://github.com/liip/LiipTestFixturesBundle/blob/2.0.0-alpha4/doc/database.md

Steps to reproduce

I updated one of my tests with these lines:

protected function setUp(): void {
    parent::setUp();
    $this->databaseTool = static::getContainer()->get(DatabaseToolCollection::class)->get(null, 'doctrine_mongodb');
}

And:

public function testSetup(): void {
    $client = static::createApiClient(); // This is basically `WebTestCase::createClient` with default values

    $this->databaseTool->loadAllFixtures(['tests']);

    $client->xmlHttpRequest('POST', '/api/setup');
    $this->assertResponseIsSuccessful();
}

Expected result

I would expect this test to run.

Actual result

I get the following error:

1) App\Tests\Controller\SetupTest::testSetup
LogicException: Booting the kernel before calling "Symfony\Bundle\FrameworkBundle\Test\WebTestCase::createClient()" is not supported, the kernel should only be booted once.

/app/vendor/symfony/framework-bundle/Test/WebTestCase.php:43
/app/tests/Controller/ApiTestCase.php:18
/app/tests/Controller/SetupTest.php:18

When only commenting the $this->databaseTool->loadAllFixtures(['tests']); line I get the same error. When also commenting the $this->databaseTool = (...) one, the test runs normally (but of course no fixture is called).

Did I get something wrong?
Thanks!

alexislefebvre commented 3 years ago

Thanks for adding that issue.

The error comes from Symfony:

Booting the kernel before calling "Symfony\Bundle\FrameworkBundle\Test\WebTestCase::createClient()" is not supported, the kernel should only be booted once.

The problem here is that static::createClient() boots a kernel, while it's already booted.

So you have to create the client first, then you should be able to fetch the container:

protected function setUp(): void {
    parent::setUp();
    $this->client = static::createClient();
    $this->databaseTool = $this->client->getContainer()
        ->get(DatabaseToolCollection::class)->get(null, 'doctrine_mongodb');
}

Then remove $client = static::createApiClient();, call $this->client instead of $client and it should work.


We should explain it in the documentation.

quentint commented 3 years ago

Thanks, that helps!

Moving on, I tried to ->loadAllFixtures(['tests']), but none of my tests-grouped fixtures were executed (although they are when I run doctrine:mongodb:fixtures:load --group=tests --env=test.

I then tried this:

$this->databaseTool->loadFixtures([
    LoadDomainData::class,
    LoadQuestionData::class,
    LoadTestUsers::class,
]);

But now I'm stuck with InvalidArgumentException: "App\DataFixtures\LoadDomainData" is not a registered fixture.

It extends Doctrine\Bundle\MongoDBBundle\Fixture\Fixture. Are MongoDB fixtures supported? I guess so, but it looks like I might have forgotten something 😕

alexislefebvre commented 3 years ago

The doctrine_mongodb loader is not tested at the moment. We'll have to investigate.

quentint commented 3 years ago

OK thanks, will investigate too.

alexislefebvre commented 3 years ago

You can try to explicitly tag the fixtures, as in https://github.com/liip/LiipTestFixturesBundle/blob/00cf42e13a58f4140aecdc27b006ea58ee83d81f/tests/App/config.yml#L41-L47

(I don't know if there's a different tag for MongoDB)

quentint commented 3 years ago

Didn't work out (tried both doctrine.fixture.orm and doctrine.fixture.odm.mongodb), still investigating.

quentint commented 3 years ago

Didn't find any solution, so I went another route, not using this bundle 😉

Here's my base test class, if anyone's interested:

<?php
namespace App\Tests\Controller;

use Doctrine\Common\DataFixtures\Executor\MongoDBExecutor;
use Doctrine\Common\DataFixtures\Purger\MongoDBPurger;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\DomCrawler\Crawler;

abstract class ApiTestCase extends WebTestCase {

    protected KernelBrowser $client;

    protected function setUp(): void {
        parent::setUp();

        // We have to create the client first, or we’ll get a "Booting the kernel before calling "(...)\WebTestCase::createClient()" is not supported, the kernel should only be booted once" error
        // See: https://symfony.com/doc/current/testing.html#retrieving-services-in-the-test
        $this->client = static::createClient();

        // Then boot the kernel
        self::bootKernel();

        // We load the test fixtures
        $fixtureLoader = static::getContainer()->get("doctrine_mongodb.odm.symfony.fixtures.loader");
        $fixtures = $fixtureLoader->getFixtures(['tests']);

        // And load them
        $dm = static::getContainer()->get('doctrine_mongodb')->getManager();
        (new MongoDBExecutor($dm, new MongoDBPurger($dm)))->execute($fixtures);
    }

}
alexislefebvre commented 3 years ago

Thanks for the feedback, we'll have to ensure that MongoDB is supported: #131

GooseBumpsOS commented 5 months ago

My solution was

self::ensureKernelShutdown();

before create client

alexislefebvre commented 5 months ago

My solution was

self::ensureKernelShutdown();

before create client

Thanks, it has been added to the documentation: