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

Performance with LiipTestFixturesBundle v2.6.0 #252

Open alexislefebvre opened 11 months ago

alexislefebvre commented 11 months ago

I am experiencing significant performance issues with LiipTestFixturesBundle version 2.6.0 when using the loadFixtures method with zero insertions. Even with an empty set of fixtures as shown below, tests take 7 to 9 seconds to run, which seems abnormally high. And without loadFixtures() 260 ms

$this->databaseTool->loadFixtures([ ExempleFixtures::class]);

 <?php

namespace App\DataFixtures;

use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;

class ExempleFixtures extends Fixture
{
    public function load(ObjectManager $manager)
    {

    }
}

Originally posted by @Dekrikh in https://github.com/liip/LiipTestFixturesBundle/issues/12#issuecomment-1833892122

alexislefebvre commented 11 months ago

@Dekrikh do the database schema has lots of entites with many columns?

You can try to keep the schema: https://github.com/liip/LiipTestFixturesBundle/issues/12#issuecomment-571355670

Dekrikh commented 11 months ago

@alexislefebvre
Yes, the reason is that generating the table takes a significant amount of time.

I measured the command's execution time using the following:

Measure-Command { php bin/console --env=test doctrine:schema:update --force } The result was:

TotalMilliseconds: 6489.8295

Now, I have good performance with https://github.com/liip/LiipTestFixturesBundle/issues/12#issuecomment-571355670, thank you.

However, I encountered another issue. In my test, I send a request with the method api of the paht ID of one. The problem is that the test doesn't start with ID 1; it uses the previous ID plus one (AUTO_INCREMENT)."

I thought of using the Event https://github.com/liip/LiipTestFixturesBundle/blob/2.x/doc/events.md to reset an AUTO_INCREMENT. Any thoughts to share with me?

alexislefebvre commented 11 months ago

@Dekrikh Try to set the id to 1 in the fixtures of the entity, it should ignore the auto increment. Or try with the event.

Dekrikh commented 11 months ago

I chose simplicity a "DELETE FROM table_name" looping over all tables with a reset of AUTO_INCREMENT = 1; at each start of the test

if someone has the same need, this code using doctrine in symfony :

public function clearAllTablesInDatabaseAndResetAutoIncrement(){
        $em = $this->getContainer()->get('doctrine.orm.entity_manager');

        $em->getConnection()->exec('SET FOREIGN_KEY_CHECKS = 0');
        // clear all the tables
        foreach ($em->getMetadataFactory()->getAllMetadata() as $metadata) {
            $queryBuilder = $em->createQueryBuilder();
            $queryBuilder->delete($metadata->getName());
            $queryBuilder->getQuery()->execute();
        }

        foreach ($em->getMetadataFactory()->getAllMetadata() as $metadata) {
            $em->getConnection()->exec('ALTER TABLE ' . $metadata->getTableName() . ' AUTO_INCREMENT = 1;');
        }

        $em->getConnection()->exec('SET FOREIGN_KEY_CHECKS = 1');
    }
alexislefebvre commented 9 months ago

@Dekrikh thanks for sharing the code. Is it faster if you keep the tables but remove the data with TRUNCATE and reset the AUTO_INCREMENT?

Dekrikh commented 9 months ago

@alexislefebvre yes, that's a better idea.

alexislefebvre commented 9 months ago

Actually, is your code already doing this? I'm not sure if the call to delete remove only the rows or the table entirely.