Laravel9无迁移文件时单元测试报数据表不存在的解决方法
问题原因
当前代码不生效的核心原因有两个:
DatabaseMigrationstrait 默认仅会加载database/migrations目录下的迁移文件,在setUp中手动调用迁移命令时未加--realpath参数,传入的base_path()生成的绝对路径会被框架识别为相对路径,导致迁移文件根本没被扫描执行。- 手动调用迁移命令时未指定测试专用数据库连接,存在迁移跑到本地开发库的风险,也会导致测试连接下没有对应表。
可行解决方案
方案1:注册测试迁移路径,保留原有trait用法
不需要在测试类setUp里手动执行Artisan命令,直接在测试环境下注册测试迁移目录即可:
- 打开
app/Providers/AppServiceProvider.php,在boot方法中添加测试环境下的迁移加载逻辑:
public function boot() { if ($this->app->environment('testing')) { $this->loadMigrationsFrom(base_path('tests/migrations')); } }
- 测试类中直接使用
DatabaseMigrationstrait即可,不需要额外写迁移执行逻辑:
class AppTest extends TestCase { use DatabaseMigrations; // 测试用例正常编写即可 }
框架运行测试时会自动扫描tests/migrations下的所有迁移文件执行,测试结束后自动回滚,不会残留数据。
方案2:手动控制迁移执行,不依赖默认trait
如果不想改服务提供者逻辑,可以去掉DatabaseMigrations trait,自己在测试生命周期里控制迁移执行和回滚,注意加上--realpath参数避免路径解析错误:
class AppTest extends TestCase { public function setUp(): void { parent::setUp(); $this->artisan('migrate', [ '--path' => base_path('tests/migrations'), '--database' => 'testing', '--realpath' => true, ]); } public function tearDown(): void { $this->artisan('migrate:rollback', [ '--path' => base_path('tests/migrations'), '--database' => 'testing', '--realpath' => true, ]); parent::tearDown(); } }
建议在phpunit.xml中配置测试环境使用内存SQLite,测试执行速度更快,也不会产生持久化数据:
<php> <env name="APP_ENV" value="testing"/> <env name="DB_CONNECTION" value="sqlite"/> <env name="DB_DATABASE" value=":memory:"/> </php>
方案3:轻量场景下直接通过Schema建表
如果需要的表结构不复杂,不需要单独维护迁移文件,直接在测试启动时用Schema门面建表即可:
use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; class AppTest extends TestCase { public function setUp(): void { parent::setUp(); if (!Schema::hasTable('{table-name}')) { Schema::create('{table-name}', function (Blueprint $table) { $table->id(); // 按业务需求定义表字段 $table->string('column1'); $table->timestamps(); }); } } public function tearDown(): void { Schema::dropIfExists('{table-name}'); parent::tearDown(); } }
内容的提问来源于stack exchange,提问作者Ahmed Amshir
相关产品推荐
相关产品推荐

