免责声明:我不是神圣实体。我所说的并不是绝对的真理。甚至不要害怕质疑世界,因为它可能是错的,而不是你。
今天,自动化测试对于维护软件的质量和完整性的重要性对于任何人来说都不是秘密,我们通常会谈论很多单元测试,但是今天,我们将更多地关注 Symfony 框架中的集成测试。
好吧好吧!如果您没有耐心阅读本文,我在下面的链接中有一个实现本文的测试项目。
https://github.com/joubertredrat/symfony-testcontainers
如今,Symfony 框架是 PHP 领域最成熟的框架之一,它拥有多个实施良好的解决方案,例如集成测试。然而,我个人总是发现,虽然自己进行集成测试很容易,但为测试提供外部依赖项并不总是那么容易,例如数据库。
即使 Docker 出现了,我仍然意识到需要以某种方式提供外部依赖项来进行测试,但是,有一个非常有趣的解决方案可以使这一步变得更加容易,Testcontainers。
Testcontainers 是一个开源框架,可让您使用 Docker 更轻松地配置所需的任何外部依赖项,例如数据库、消息代理、缓存系统或几乎任何容器依赖项。
Testcontainers 与 Docker compose 或任何其他形式的容器配置相关的最大区别在于,您可以对容器配置进行编程,现在它已经支持 Golang、Java、.NET、Node.js、Python、Rust、其他几种语言,当然还有 PHP!
我第一次接触 Testcontainers 是在一个 Golang 项目中,我真的很喜欢配置 MongoDB 容器来在存储库中执行测试的便利性,之后,我决定在我的个人项目中做同样的事情使用 Symfony 框架的 PHP。
Symfony 的一大优势正是通过提供功能齐全的内核来执行测试所需的引导程序来支持 PHPUnit 中的测试。
虽然 Testcontainers 支持 PHP,但实现较新,您可以在 https://github.com/testcontainers/testcontainers-php 查看。
下面我们有一个 MySQL 8.0 容器的实现,它是这个项目的外部依赖,除了启动 Symfony 内核、创建数据库和模式之外。
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(); } }
有了这个,我们就有了实际执行测试的类的基类,如下例所示。
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); } }
运行测试套件时,您会注意到完成测试的延迟,但是,这是正常的,因为在此过程中,Testcontainers 正在配置您定义在测试中使用的容器。
最后,通过这种轻松,您甚至可以尝试做一些疯狂的事情,例如 100% 覆盖率。不相信吗?您可以在 https://joubertredrat.github.io/symfony-testcontainers 上亲自查看。
就这样吧,下次再见!
以上是Symfony 中与 Testcontainers 的集成测试的详细内容。更多信息请关注PHP中文网其他相关文章!