Maison > Article > développement back-end > Tests d'intégration dans Symfony avec Testcontainers
Avertissement : je ne suis pas une entité divine. Ce que je dis n'est pas une vérité absolue. N'ayez pas peur de remettre en question même le monde, car il pourrait avoir tort, pas vous.
Aujourd'hui, ce n'est un secret pour personne l'importance des tests automatisés pour maintenir la qualité et l'intégrité de vos logiciels et on parle généralement beaucoup de tests unitaires, cependant, aujourd'hui, nous nous concentrerons davantage sur les tests d'intégration dans le Framework Symfony.
D'accord, d'accord ! Si vous n'avez pas la patience de lire cet article, j'ai un projet test implémentant cet article sur le lien ci-dessous.
https://github.com/joubertredrat/symfony-testcontainers
Aujourd'hui, le Framework Symfony est l'un des frameworks les plus matures de l'univers PHP et il dispose de plusieurs solutions bien implémentées, comme pour les tests d'intégration par exemple. Cependant, personnellement, j'ai toujours trouvé que même s'il est facile de faire les tests d'intégration eux-mêmes, fournir des dépendances externes pour les tests n'était pas toujours aussi simple, comme les bases de données par exemple.
Même avec l'émergence de Docker, j'ai toujours réalisé la nécessité de provisionner des dépendances externes d'une manière ou d'une autre pour les tests, cependant, il existe une solution très intéressante qui peut rendre cette étape beaucoup plus facile, Testcontainers.
Testcontainers est un framework open source qui vous permet de provisionner plus facilement toute dépendance externe dont vous avez besoin à l'aide de Docker, comme une base de données, un courtier de messages, des systèmes de mise en cache ou pratiquement n'importe quelle dépendance de conteneur.
La grande différence entre Testcontainers par rapport à Docker Compose ou à toute autre forme de provisionnement de conteneurs est que vous pouvez programmer le provisionnement de conteneurs, et aujourd'hui, il prend déjà en charge Golang, Java, .NET, Node.js, Python, Rust, plusieurs autres langages, et bien sûr, PHP !
Mon premier contact avec Testcontainers a été avec un projet Golang et j'ai beaucoup aimé la facilité de provisionner un conteneur MongoDB pour réaliser mes tests dans les référentiels et après cela, j'ai décidé de faire de même dans un projet personnel que j'ai en PHP utilisant le Framework Symfony.
L'un des grands avantages de Symfony est précisément la prise en charge des tests dans PHPUnit en fournissant un noyau entièrement fonctionnel pour effectuer le bootstrap nécessaire aux tests.
Bien que Testcontainers prenne en charge PHP, l'implémentation est plus récente et vous pouvez la consulter sur https://github.com/testcontainers/testcontainers-php.
Ci-dessous, nous avons une implémentation d'un conteneur MySQL 8.0, qui est la dépendance externe de ce projet, en plus du démarrage du noyau Symfony, de la création de la base de données et du schéma.
class IntegrationTestCase extends KernelTestCase { protected static ?MySQLContainer $container = null; public static function setUpBeforeClass(): void { parent::setUpBeforeClass(); if (!static::$container) { static::$container = MySQLContainer::make('8.0', 'password'); static::$container->withPort('19306', '3306'); static::$container->run(); $kernel = self::bootKernel(); $container = $kernel->getContainer(); $application = new Application($kernel); $application->setAutoExit(false); $application->run( new ArrayInput(['command' => 'doctrine:database:create', '--if-not-exists' => true]) ); $entityManager = $container->get('doctrine')->getManager(); $metadata = $entityManager->getMetadataFactory()->getAllMetadata(); $schemaTool = new SchemaTool($entityManager); $schemaTool->dropSchema($metadata); $schemaTool->createSchema($metadata); } } public static function tearDownAfterClass(): void { parent::tearDownAfterClass(); if (static::$container instanceof MySQLContainer) { static::$container->remove(); } }
Avec cela, nous avons la classe de base pour les classes qui exécuteront réellement les tests, comme dans l'exemple ci-dessous.
class UserRepositoryTest extends IntegrationTestCase { public function testSave(): void { $user = new User(); $user->setName('John Doe'); $user->setEmail('john@doe.local'); $repo = $this->getRepository(); $repo->save($user, true); self::assertNotNull($user->getId()); self::assertIsInt($user->getId()); self::assertTrue($user->getId() > 0); } public function testGetByEmail(): void { $user = new User(); $user->setName('John Doe'); $user->setEmail('john2@doe.local'); $repo = $this->getRepository(); $userNotFound = $repo->getByEmail($user->getEmail()); self::assertNull($userNotFound); $repo->save($user, true); $userFound = $repo->getByEmail($user->getEmail()); self::assertEquals($user->getEmail(), $userFound->getEmail()); } protected function tearDown(): void { parent::tearDown(); $connection = $this ->getContainer() ->get('doctrine') ->getManager() ->getConnection() ; $connection->executeStatement('TRUNCATE TABLE users'); } protected function getRepository(): UserRepository { return $this->getContainer()->get(UserRepository::class); } }
Lors de l'exécution de la suite de tests, vous remarquerez un retard dans la fin des tests, cependant, cela est normal, car pendant ce processus, Testcontainers provisionne le conteneur que vous avez défini pour utiliser dans les tests.
Enfin, avec cette facilité, vous pouvez même tenter de faire des choses folles, comme une couverture à 100%. Vous n'y croyez pas ? Vous pouvez le voir vous-même sur https://joubertredrat.github.io/symfony-testcontainers.
Alors c'est tout, à la prochaine fois !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!