为啥 phpunit 没有得到 phpunit.xml 中指定的正确 APP_ENV?

Posted

技术标签:

【中文标题】为啥 phpunit 没有得到 phpunit.xml 中指定的正确 APP_ENV?【英文标题】:Why phpunit is not getting the correct APP_ENV as specified in phpunit.xml?为什么 phpunit 没有得到 phpunit.xml 中指定的正确 APP_ENV? 【发布时间】:2018-02-05 22:07:14 【问题描述】:

我正在使用 Laravel,这是我的 ./phpunit.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="bootstrap/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="FeatureTests">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>

        <testsuite name="UnitTests">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="DB_CONNECTION" value="sqlite_testing" />
    </php>
</phpunit>

我正在使用以下命令触发我的一个测试套件:

./vendor/phpunit/phpunit/phpunit --testsuite UnitTests

在我的测试方法中,我有:

public function testAllMandatoryData()

   dump(env('APP_ENV'));
   ....

它显示“本地”,我期待 phpunit.xml 中指定的“测试”

         <env name="APP_ENV" value="testing"/>

编辑:附加细节 我在 Docker 容器中运行了这个 laravel 应用程序

在 docker-compose.yml 我设置了一些环境变量,例如:

environment:
  - APP_ENV=local
  - DB_HOST=192.168.0.22
  - DB_PORT=33306
  - DB_DATABASE=mydatabase
  - DB_USERNAME=homestead
  - DB_PASSWORD=homestead

我注意到 phpunit.xml 中的指令如下:

    <env name="APP_ENV" value="testing"/>

当名称已经在 docker-compose 中时无效。

相反,如果我添加一些未在 docker-compose.yml 中定义的内容,将在 phpunit 运行时正确设置,例如:

    <env name="DB_CONNECTION" value="sqlite_test"/>

结束编辑

我错过了什么?

谢谢

【问题讨论】:

我不确定您是否可以在应用程序级别覆盖容器变量?也许这些帮助:github.com/docker/compose/issues/3183, philippe.bourgau.net/… 【参考方案1】:

使用

<env name="APP_ENV" value="testing" force="true"/>
<env name="CACHE_DRIVER" value="array" force="true"/>
<env name="SESSION_DRIVER" value="array" force="true"/>
<env name="QUEUE_DRIVER" value="sync" force="true"/>
<env name="DB_CONNECTION" value="sqlite_testing" force="true"/>

如果没有 force 参数,它将无法工作。看到这个问题: https://github.com/sebastianbergmann/phpunit/issues/2353 和合并后的 PR:https://github.com/sebastianbergmann/phpunit/pull/2723

【讨论】:

@koalaok 这应该是选择的答案,这样您仍然可以在 docker-compose 文件中使用这些环境参数【参考方案2】:

我尝试用我找到的最佳选择来回答自己。

如果您在 docker-compose.yml 文件中设置 ENV 变量,您将无法使用 phpunit.xml 指令覆盖它们,例如:

  <env name="APP_ENV" value="testing"/>

那么您应该选择从 docker-compose.yml 中删除(如本例中的)APP_ENV 变量集

并依赖 .env Laravel 文件

APP_ENV=local

通过此设置,phpunit 将能够将 APP_ENV 覆盖为“测试”

我仍然不是 100% 确定需要这种安排,所有 docker 代理版本。我拥有的另一个 Docker 版本的主机表现不同。

【讨论】:

【参考方案3】:

请改用config('app.env')env() 值可能会被缓存,在这种情况下 php artisan config:clear 可能会有所帮助,尽管我在从命令行环境访问 env 值时也遇到了问题。

更多信息here 和 here。

【讨论】:

谢谢,但您的任何建议都不适合我。 为什么不呢?如果您不向我们提供详细信息,任何人都无法提供帮助。 添加了我目前发现的一些细节。 使用 php artisan config:clear 为我工作,并允许我的测试针对测试数据库运行。它们应该是一种更好的测试方法,以使其始终连接到测试数据库,并且不会在不清除此配置的情况下覆盖主数据库。当我重新启动 docker setup 时,配置又回来了,所以每次我重新启动容器时都需要这样做。 仅供参考:它将是 config('app.env');。 config 函数使用点表示法。 config('APP_ENV') 将始终为空。【参考方案4】:

我遇到了同样的问题,.env 变量似乎覆盖了我的 phpunit.xml 中的变量,以下是一些可行的解决方案:

    指定运行phpunit时使用哪个phpunit.xml文件,它可能使用了错误的文件。 vendor/bin/phpunit --configuration [path to your phpunit.xml] 清理配置缓存。 php artisan config:cache 如果您在 Docker 容器中,上述操作可能不适合您。我所做的是手动删除 bootstrap/cache 文件。

希望对你有帮助!

【讨论】:

对于我的情况,我使用的是 laradock,所以我删除了我的本地引导程序/缓存运行测试并且它工作了【参考方案5】:

我在使用 Docker 和 docker-compose 时遇到了同样的问题,事实上我的 docker-compose.yml 正在加载 Laravel 的 .env 文件。 所以,我通过创建一个 .env.docker 文件并设置(在 docker-compose.yml 中)来解决它:

  env_file:
    - .env.docker

它就像一个魅力,PHPUnit 能够选择我的 .env.testing 文件 insted .env

【讨论】:

【参考方案6】:

尝试通过运行命令php artisan config:clear 清除配置缓存。这是因为您可能在运行测试之前运行了命令php artisan config:cache,并且您的APP_ENV 被缓存为local

【讨论】:

【参考方案7】:

我不得不求助于这个小技巧来让环境“测试”,我不得不把它放在TestCase.php

protected function setUp(): void

   parent::setUp();
   $this->app->detectEnvironment( function () 
      return 'testing';
   );

【讨论】:

【参考方案8】:

对于 docker 用户,我在 composer.json 文件中添加了一个新的 test 脚本:

"test": [
        "DB_CONNECTION=sqlite && DB_DATABASE=:memory: && APP_ENV=testing && phpunit --colors=always --no-coverage"
        ],

这个脚本只是覆盖了docker-compose.json中定义的环境变量

【讨论】:

以上是关于为啥 phpunit 没有得到 phpunit.xml 中指定的正确 APP_ENV?的主要内容,如果未能解决你的问题,请参考以下文章

PHPUnit测试使用pdo的受保护静态方法

phpunit 测试返回 302 验证错误,为啥不返回 422

为啥我在测试创建相同类的 phpUnit 静态方法后得到“无法加载模拟 MyClassConsumer,类已存在”?

为啥当我运行我的 phpunit 测试时,我得到一个空响应,但 Postman 中的相同路由/用户的行为符合预期?

为啥在 Laravel 中使用 PHPUnit 的函数“link_to”没有返回值?

为啥 Laravel 中的 PHPUnit 不能访问存在的路由?