迁移数据库以测试Laravel的模式
P粉722409996
P粉722409996 2023-08-26 17:09:54
[PHP讨论组]

问题

  • 我正在使用 Laravel 8.83.23
  • 我有来自压缩迁移的模式转储文件,位于 database\schema\mysql-schema.dump
  • 测试运行在测试数据库上,就像在 database.php 中一样
'testing' => [
                    'driver' => 'mysql',
                    'host' => env('DB_TEST_HOST', '127.0.0.1'),
                    'port' => env('DB_TEST_PORT', '3306'),
                    'database' => env('DB_TEST_DATABASE', 'forge'),
                    'username' => env('DB_TEST_USERNAME', 'forge'),
                    'password' => env('DB_TEST_PASSWORD', ''),
                ],
  • 在我压缩迁移之前,我的测试用例只使用了 DatabaseMigrations trait,并且测试数据库每次都会被重新创建,一切正常,以下是一个测试类的示例:
class SystemControllerTest extends TestCase
    {
        use WithFaker;
        use DatabaseMigrations;
        /**
         * @var User
         */
        private $user;
    
        public function setUp(): void
        {
            parent::setUp();
    
            //创建角色和数据
            $this->seed(RoleAndPermissionSeeder::class);
        ... 等等
  • 迁移被找到并执行,重新创建了数据库
  • 然后,我压缩了迁移,所以所有的迁移都被删除了,我得到了 database\schema\mysql-schema.dump
  • php artisan migrate 通过命令行按预期工作,从转储文件中创建完整的数据库模式(它找到了它)
  • 然而,测试不再工作,因为出现了一个错误
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'cinema_test.roles' doesn't exist (SQL: delete from `roles`)
  • 当我在测试运行后检查 sql 测试数据库时,它是空的(只有表 migrations 被创建,而且是空的)
  • 即使在测试的设置中调用 artisan migrate,这个错误仍然存在:
public function setUp(): void
        {
            parent::setUp();
            Artisan::call('migrate', array(
       '--database' => 'testing',
       '--force' => true));
            //它在这里崩溃
            $this->seed(RoleAndPermissionSeeder::class);
  • RoleAndPermissionSeeder 只操作不存在的 sql 表,因此出现错误
  • 我甚至尝试了 DatabaseMigrationsDatabaseTransactionsRefreshDatabase traits,但都没有成功
  • 我如何填充数据库数据?我无法读取 Artisan::call('migrate') 命令的输出,所以我不知道那里发生了什么
  • Artisan::call('migrate') 的返回代码是 0
  • 我是否可能遗漏了一些设置?

P粉722409996
P粉722409996

全部回复(1)
P粉821274260

我终于弄清楚了。

问题的原因

问题出在测试环境的设置不正确。我没有找到确切的原因,但我找到了如何设置测试环境以便找到并加载转储文件。

我如何追踪错误

这描述了我找到解决方法的步骤。

database.php中,我复制了测试数据库而不是正常的数据库
  • database.php中,我有主数据库连接:
'mysql' => [
                'driver' => 'mysql',
                'url' => env('DATABASE_URL'),
                'host' => env('DB_HOST', '127.0.0.1'),
                'port' => env('DB_PORT', '3306'),
                'database' => env('DB_DATABASE', 'forge'),
                'username' => env('DB_USERNAME', 'forge'),
                'password' => env('DB_PASSWORD', ''),
                'unix_socket' => env('DB_SOCKET', ''),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'prefix_indexes' => true,
                'strict' => false,
                'engine' => null,
                'options' => extension_loaded('pdo_mysql') ? array_filter([
                    PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
                ]) : [],
            ],

和测试连接

'testing' => [
                    'driver' => 'mysql',
                    'host' => env('DB_TEST_HOST', '127.0.0.1'),
                    'port' => env('DB_TEST_PORT', '3306'),
                    'database' => env('DB_TEST_DATABASE', 'forge'),
                    'username' => env('DB_TEST_USERNAME', 'forge'),
                    'password' => env('DB_TEST_PASSWORD', ''),
                ],
  • 我将testing连接数据复制到一个新的mysql连接中,只是为了看看在命令行上是否得到相同的结果
  • 所以,文件现在看起来像这样
'mysql' => [
                'url' => env('DATABASE_URL'),
                'driver' => 'mysql',
                    'host' => env('DB_TEST_HOST', '127.0.0.1'),
                    'port' => env('DB_TEST_PORT', '3306'),
                    'database' => env('DB_TEST_DATABASE', 'forge'),
                    'username' => env('DB_TEST_USERNAME', 'forge'),
                    'password' => env('DB_TEST_PASSWORD', ''),
                'unix_socket' => env('DB_SOCKET', ''),
                'charset' => 'utf8mb4',
                'collation' => 'utf8mb4_unicode_ci',
                'prefix' => '',
                'prefix_indexes' => true,
                'strict' => false,
                'engine' => null,
                'options' => extension_loaded('pdo_mysql') ? array_filter([
                    PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
                ]) : [],
            ],
    
    /*'testing' => [
                    'driver' => 'mysql',
                    'host' => env('DB_TEST_HOST', '127.0.0.1'),
                    'port' => env('DB_TEST_PORT', '3306'),
                    'database' => env('DB_TEST_DATABASE', 'forge'),
                    'username' => env('DB_TEST_USERNAME', 'forge'),
                    'password' => env('DB_TEST_PASSWORD', ''),
                ],*/
  • 在控制台上,我运行了php artisan:migrate
  • 数据库转储文件被找到并加载
  • 因此,在正常情况下找到了转储文件,但在测试情况下没有找到
  • 经过一些研究,我在phpunit.xml中更改了测试环境的设置,我现在将解释它
文件phpunit.xml

phpunit.xml如下所示(此处未显示完整文件):

<server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
        <env name="DB_CONNECTION" value="testing"/>     
    </php>
</phpunit>
  • 所以,我们可以看到测试数据库连接被定义为单元测试
  • 在网上我找到了建议,只设置数据库表,而不是为测试更改整个连接,因为这样更容易
  • 我尝试了这样的方法,所以phpunit.xml变成了
<server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <server name="TELESCOPE_ENABLED" value="false"/>
        <env name="DB_DATABASE" value="cinema_test"/>   
    </php>
</phpunit>
  • 我从database.php中删除了测试连接,并从.env文件中删除了相关的过时变量
  • 这修复了问题,现在转储文件在测试中也被加载了
结论

虽然我没有找到真正导致Laravel无法加载转储文件的原因,但我找到了一个解决方法,即仅为测试更改数据库名称,而不是为测试目的定义全新的SQL连接。这解决了问题,现在在测试期间数据库转储文件会被加载。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号