Codeception & Symfony - 在测试前运行 Doctrine 迁移

Posted

技术标签:

【中文标题】Codeception & Symfony - 在测试前运行 Doctrine 迁移【英文标题】:Codeception & Symfony - run Doctrine migrations before tests 【发布时间】:2018-10-06 10:11:27 【问题描述】:

我有一个 Symfony 4 应用程序和 Doctrine with Doctrine 迁移。我正在引入 Codeception 来运行 API 测试,并且需要在测试运行之前运行迁移。由于我使用的是Doctrine2 module,我真的不想同时包含DB module,因为测试不需要它,并且需要在两个不同的位置配置测试数据库。

我目前正在使用Symfony module,我注意到Laravel module 有一个run_database_migrations 配置选项。

在测试之前,在 Symfony 应用程序中运行 Doctrine 迁移命令的最佳方式是什么? (bin/console doctrine:migrations:migrate -n是具体的命令)。


编辑我有一个解决方案,虽然它有效,但远非理想。通过使用 Codeception Customisation,我创建了以下扩展,基本上手动 execs 底层 Symfony 命令。

class DatabaseMigrationExtension extends Extension

    public static $events = [
        Events::SUITE_BEFORE => 'beforeSuite',
    ];

    public function beforeSuite(SuiteEvent $e)
    
        echo(exec('bin/console doctrine:database:drop --force') . php_EOL);
        echo(exec('bin/console doctrine:database:create') . PHP_EOL);
        echo(exec('bin/console doctrine:migrations:migrate -n') . PHP_EOL);
    


编辑 2 这样做的目的基本上是复制与 Codeception DB 模块类似的功能,它允许您提供它在测试中自动使用的数据库的 SQL 转储,但是而是使用 Doctrine 迁移来处理数据库。 - https://codeception.com/docs/modules/Db#sql-data-dump

【问题讨论】:

【参考方案1】:

我花了一段时间尝试了几种不同的方法来实现这一目标。我最初使用RunProcess,但这似乎会导致数据库被删除而不是重新创建的零星问题,尽管使用了睡眠配置。我最终只是更新了现有的扩展以使用 CLI 模块,它可以按需要工作(无需创建脚本或运行多个命令),也无需使用 exec

最终延期;

class DatabaseMigrationExtension extends Extension

    public static $events = [
        Events::SUITE_BEFORE => 'beforeSuite',
    ];

    public function beforeSuite()
    
        try 
            /** @var \Codeception\Module\Cli $cli */
            $cli = $this->getModule('Cli');

            $this->writeln('Recreating the DB...');
            $cli->runShellCommand('bin/console doctrine:database:drop --if-exists --force');
            $cli->seeResultCodeIs(0);
            $cli->runShellCommand('bin/console doctrine:database:create');
            $cli->seeResultCodeIs(0);

            $this->writeln('Running Doctrine Migrations...');
            $cli->runShellCommand('bin/console doctrine:migrations:migrate --no-interaction');
            $cli->seeResultCodeIs(0);

            $this->writeln('Test database recreated');
         catch (\Exception $e) 
            $this->writeln(
                sprintf(
                    'An error occurred whilst rebuilding the test database: %s',
                    $e->getMessage()
                )
            );
        
    

并注册;

// codeception.yml
extensions:
    enabled:
        - \DatabaseMigrationExtension

输出(-vv 或更高版本还显示 DB & Migration 命令的输出);

【讨论】:

【参考方案2】:

我总是创建一个 bash 脚本来执行此操作,或者一个 Makefile。

bash 命令

我的./runtests.sh 脚本包含

#!/bin/bash
./bin/console command:for:migrations
./bin/phpunit

生成文件

与 Makefile 相同

.FOO: testsuite
testsuite:
    ./runtests.sh

.FOO: testsuite
testsuite:
    ./bin/console command:for:migrations
    ./bin/phpunit

为什么我更喜欢 Makefile

最近我在我的 .bash_profile 中添加了这个脚本,它允许我从 bash 中自动完成 makefile 中的所有目标(非常简单,因为您不再需要记住所有命令,只需要记住 maketab)。

完成 -W "`grep -oE '^[a-zA-Z0-9_.-]+:([^=]|$)' Makefile | sed 's/[^a-zA-Z0-9_ .-]*$//'`" 制作

因此,.. 您可以创建如下目标:

运行测试 runtests_with_fixtures 迁移 runtests_with_migrations ...

等等

我的建议是创建您自定义的简单方式来运行命令。


这是一种运行所有或只运行一个命令的方法 usgin make

.FOO: dropforce
dropforce:
    bin/console doctrine:database:drop --force

.FOO: dbcreate
dbcreate:
    bin/console doctrine:database:create

.FOO: migrate
migrate:
    bin/console doctrine:migrations:migrate

.FOO: suite
suite: dropforce dbcreate migrate

【讨论】:

感谢您的深入回答 - 我很高兴以这种方式作为后备方案取得进展,但理想情况下,我希望由测试套件处理数据库(创建、迁移),而不是外部处理因为测试套件已经在测试环境(而不是开发)中运行并处理清理/拆卸。我上面的hacky解决方案为我做了这个,所以运行测试不需要任何事先设置,它都在测试命令中处理,并根据测试本身也运行的测试环境变量设置数据库。 【参考方案3】:

使用 Codeception 4,您无需 Cli 模块即可:

$symfony = $this->getModule('Symfony');

$symfony->runSymfonyConsoleCommand('doctrine:database:drop',['--if-exists'=>true, '--force'=>true]);
$symfony->runSymfonyConsoleCommand('doctrine:database:create');
$symfony->runSymfonyConsoleCommand('doctrine:migrations:migrate', ['--no-interaction'=>true]);

【讨论】:

以上是关于Codeception & Symfony - 在测试前运行 Doctrine 迁移的主要内容,如果未能解决你的问题,请参考以下文章

Mockery, Codeception 和 Symfony - 无法重新声明类

在功能测试中使用全局变量(使用 Symfony 和 Codeception)

如何从 codeception & phantomjs 测试中获取当前 url?

Symfony 4 模拟私人服务

Composer 更新 codeception - phpunit 不更新

如何跳过 Codeception cest 测试