Laravel测试用例运行失败 执行seed时报错不存在settings表如何解决
根因分析
Laravel 服务提供者的boot方法执行优先级远高于测试用例的setUp方法,测试启动时会先运行所有服务提供者的boot逻辑,此时你写的迁移、数据填充代码还未执行,settings表不存在,因此触发SQL报错。
解决方案
方案1:服务提供者加表存在判断(最简便)
修改AppServiceProvider的boot代码,仅在settings表存在时才执行查询:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Schema; use App\Models\Setting; class AppServiceProvider extends ServiceProvider { public function boot() { // 先判断表是否存在,不存在就跳过查询 if (Schema::hasTable('settings')) { config(['settings' => Setting::get(['id','name','setting_value'])]); } } }
该方案无需修改测试代码,同时不影响生产环境正常逻辑。
方案2:将配置查询改为延迟加载(更优雅)
不要在服务提供者boot阶段提前加载配置,改为第一次使用时再查询:
- 先删除
AppServiceProvider里的settings配置写入逻辑 - 新增全局辅助函数,调用时再加载配置:
if (! function_exists('settings')) { function settings(?string $key = null, mixed $default = null): mixed { static $isLoaded = false; if (! $isLoaded) { $isLoaded = true; if (Schema::hasTable('settings')) { $settings = Setting::get(['id','name','setting_value'])->keyBy('name'); config(['settings' => $settings]); } } return config('settings.'.$key, $default); } }
后续业务代码中调用settings()方法获取配置即可,测试运行时第一次调用配置,setUp方法已经执行完毕,迁移已经完成,不会出现表不存在的报错。
额外优化项
你当前的测试用例中同时使用了RefreshDatabase和DatabaseMigrations两个Trait,功能重叠会导致重复执行迁移,建议仅保留RefreshDatabase,同时可以删除setUp方法中手动执行migrate:fresh的代码,RefreshDatabase会自动处理测试数据库的重置逻辑。
内容的提问来源于stack exchange,提问作者Aayush Dahal
相关产品推荐
相关产品推荐

