>  기사  >  백엔드 개발  >  Testcontainers를 사용한 Symfony의 통합 테스트

Testcontainers를 사용한 Symfony의 통합 테스트

WBOY
WBOY원래의
2024-09-12 10:23:00468검색

면책조항: 저는 신성한 존재가 아닙니다. 내가 말하는 것은 절대적인 진실은 아니다. 세상에 질문하는 것을 두려워하지 마세요. 당신이 아니라 틀릴 수도 있으니까요.

오늘은 소프트웨어의 품질과 무결성을 유지하기 위한 자동화된 테스트의 중요성은 누구에게도 비밀이 아니며 일반적으로 단위 테스트에 대해 많이 이야기하지만 오늘은 Symfony Framework에 대한 통합 테스트에 더 중점을 둘 것입니다.

인내심이 없어요. 코드를 보여주세요!

알았어 알았어! 기사를 읽는 데 인내심이 없으시다면 아래 링크에 이 기사를 구현한 테스트 프로젝트가 있습니다.

https://github.com/joubertredrat/symfony-testcontainers

Symfony 프레임워크 및 통합 테스트

현재 Symfony Framework는 PHP 세계에서 가장 성숙하고 안정적인 프레임워크 중 하나이며, 예를 들어 통합 테스트와 같이 훌륭하게 구현된 다양한 솔루션을 보유하고 있습니다. 하지만 개인적으로 통합 테스트 자체는 쉽지만, 테스트를 위해 외부 종속성을 제공하는 것은 데이터베이스처럼 항상 쉽지만은 않다고 생각했습니다.

Docker와 같은 솔루션을 사용하더라도 테스트를 위한 방식으로 외부 종속성을 제공해야 할 필요성을 여전히 깨달았지만, 이 단계를 훨씬 쉽게 만들 수 있는 매우 흥미로운 솔루션인 Testcontainers가 존재합니다.

테스트 컨테이너

Testcontainers는 Docker를 사용하여 데이터베이스, 메시지 브로커, 캐시 시스템 또는 컨테이너의 종속성으로 필요한 외부 종속성을 쉽게 제공할 수 있는 오픈 소스 프레임워크입니다.

Docker 작성 또는 기타 컨테이너 오케스트레이션 방식과 관련하여 Testcontainers의 가장 큰 장점은 컨테이너 프로비저닝을 코딩할 수 있다는 것이며 현재 이미 Golang, Java, .NET, Node.js, Python, Rust 등을 지원하고 있습니다. 다른 언어는 물론 PHP도 가능합니다!

Testcontainers를 처음 접한 것은 Golang의 프로젝트였으며 MongoDB 컨테이너를 프로비저닝하여 리포지토리 테스트를 수행하는 기능이 너무 마음에 들었고 그 후 Symfony Framework를 사용하여 PHP의 개인 프로젝트에서도 동일한 작업을 수행하기로 결정했습니다.

Symfony 테스트 컨테이너 = ❤️

Symfony의 가장 큰 장점 중 하나는 테스트에 필요한 부트스트랩을 수행하기 위해 PHPUnit 및 기능적 커널과 통합된 테스트를 수행할 수 있다는 점입니다.

테스트 컨테이너는 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가 테스트에 사용하도록 정의한 컨테이너를 프로비저닝하기 때문입니다. .

Integration tests on Symfony with Testcontainers

Integration tests on Symfony with Testcontainers

마지막으로 이 시설을 사용하면 100% 보장과 같은 말도 안되는 일을 할 수 있습니다. 믿을 수 없습니까? https://joubertredrat.github.io/symfony-testcontainers에서 직접 확인하실 수 있습니다.

그렇습니다. 다음에 만나요!

위 내용은 Testcontainers를 사용한 Symfony의 통합 테스트의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.