Laravel 8测试时config()函数取值异常问题排查
问题:Laravel 8测试时env()与config()取值不一致
环境与异常现象
基于Laravel 8 + Laravel Sail的应用,执行sail artisan test运行测试时出现异常:
env()函数能正确获取phpunit.xml中覆盖的配置值config()函数却读取到.env文件里的旧值
相关配置
phpunit.xml 配置片段
<php> <server name="APP_ENV" value="testing" force="true"/> <server name="BCRYPT_ROUNDS" value="4"/> <server name="CACHE_DRIVER" value="array"/> <server name="DB_CONNECTION" value="sqlite" force="true"/> <server name="DB_DATABASE" value=":memory:"/> <server name="DB_LEGACY_CONNECTION" value="sqlite" /> <server name="DB_LEGACY_DATABASE" value=":memory:" /> </php>
.env 配置片段
APP_PORT=49200 APP_NAME=Laravel APP_ENV=local DB_CONNECTION=mysql DB_HOST=mysql DB_PORT=3306 FORWARD_DB_PORT=33061 DB_DATABASE=lb_backend DB_USERNAME=sail DB_PASSWORD=sail
测试代码与输出
Pest测试的beforeEach方法中打印变量:
beforeEach(function () { $env_vars = [ env('APP_ENV', 'production'), // 返回testing config('app.env'), // 返回local env('DB_CONNECTION', 'mysql'), // 返回sqlite config('database.default') // 返回mysql ]; fwrite(STDERR, print_r($env_vars, TRUE)); $this->usingInMemoryDatabase(); // 返回false,内部调用config('database.default') // ... });
核心配置文件片段
config/app.php
<?php return [ // ... /* |-------------------------------------------------------------------------- | Application Environment |-------------------------------------------------------------------------- | | This value determines the "environment" your application is currently | running in. This may determine how you prefer to configure various | services the application utilizes. Set this in your ".env" file. | */ 'env' => env('APP_ENV', 'production'), // ... ];
config/database.php
<?php return [ /* |-------------------------------------------------------------------------- | Default Database Connection Name |-------------------------------------------------------------------------- | | Here you may specify which of the database connections below you wish | to use as your default connection for all database work. Of course | you may use many connections at once using the Database library. | */ 'default' => env('DB_CONNECTION', 'mysql'), // ... ];
原因与解决方案
这不是Laravel或Sail的Bug,是配置加载顺序导致的问题:
Laravel启动时会先加载.env文件,紧接着加载所有config/*.php配置文件,此时配置文件会把当时的环境变量值缓存到配置数组中。而phpunit.xml里的<server>配置是在Laravel应用初始化完成后才设置的环境变量,所以config()读取的是初始化时缓存的旧值,而env()直接读取当前环境变量,因此能拿到新值。
解决方法
方法一:测试时重新初始化应用
在beforeEach中调用refreshApplication(),强制重新加载配置:
beforeEach(function () { $this->refreshApplication(); // 后续测试代码... });
方法二:使用.env.testing文件
创建.env.testing文件,写入测试环境专属配置:
APP_ENV=testing DB_CONNECTION=sqlite DB_DATABASE=:memory: # 其他测试环境需要的配置
Laravel运行测试时会自动优先加载.env.testing,无需修改phpunit.xml,配置加载时就能读取到正确的值。
方法三:调整phpunit.xml的bootstrap流程
确保phpunit的bootstrap文件在Laravel初始化前就设置好环境变量,不过前两种方法更简单直接。
内容的提问来源于stack exchange,提问作者C. Celora
相关产品推荐
相关产品推荐

