Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ShaneTurner's avatar

phpunit.xml not being read, using variables from .env

I can't get tests to run from a testing environment, they always seem to run using the 'local' variables set in the .env file rather than the settings in phpunit.xml

I've run.

php artisan config:clear

my phpunit.xml

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

        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="BCRYPT_ROUNDS" value="4"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="MAIL_DRIVER" value="array"/>
        <env name="DB_CONNECTION" value="sqlite"/>
        <env name="DB_DATABASE" value=":memory:"/>
    </php>
</phpunit>

But if I echo out the APP_ENV variable in testing

dump(env('APP_ENV'));

I still get it showing "local"

Anyone run into this problem before?

0 likes
29 replies
Cronix's avatar

don't check env(), check config(). Whatever is in config, is what's actually being used.

dump(config('app.env'));
1 like
ShaneTurner's avatar

Thanks for that.

Tried

dump(config('app.env'));

But got the same result: "local"

click's avatar

How do you run your phpunit tests? Do you run them from your command line or with some IDE?

If you run from the command line try adding --configuration /path/to/file.xml to it see the docs: https://phpunit.de/manual/6.5/en/textui.html

I always run them from within PHPStorm. And there is an option to define the phpunit.xml path. Preferences > Languages & Frameworks > PHP > Test Frameworks and there is an option to define the default configuration path.

3 likes
ShaneTurner's avatar

Usually from the command line. With and without the config flag using absolute path.

Most frustrating. Can't run tests because they nuke my live dev database.

3 likes
click's avatar

Mmm, can you figure out if it is now using your phpunit.xml file at all or only the environment settings?

Can you for example a different bootstrap file? And see if it passes that file

bootstrap="vendor/autoload.php"

ShaneTurner's avatar

Hmm.

Right made alternative bootloader file testautoload.php

Same content but with an additional global variable to test.

$GLOBALS['bootload'] = "Testing New Loader";

And in the test file:

dump($GLOBALS['bootload']);

Running phpunit prints: "Testing New Loader", so at least I now know that the phpunit.xml is being read.

But it would appear system variables are somehow still being set and overriding the ones specified in the phpunit.xml file.

ShaneTurner's avatar

Anyone else got some suggestions, I just can't figure this one out.

Could always go the ol' reliable clean slate rebuild on the OS.

click's avatar

I don't have a solution. But are all of the ENV variables in your phpunit.xml ignored? Or only the config('app.env') ? What Laravel version are you using? And how does your test look like? Do you have a default Laravel test or do you have your own setUp methods maybe?

ShaneTurner's avatar

For some reason it was persisting the environment variables to the system, and they were taking precedence.

I couldn't figure out why, or how to stop it. So I nuked the HDD.

Got a fresh OS, and the problem has magically vanished. I guess the cause will remain a mystery.

But for historical records:

Laravel: 5.6* Tests were stock, with one simple create user, update user, verify name on page. No custom setUp or teardowns.

1 like
ShaneTurner's avatar

Solved the issue.

It turned out to be my shell. ZSH in this case. No idea what or why.

1 like
jplhomer's avatar

@SHANETURNER - I'm running into this exact issue with a fresh install of Laravel 5.8 :( trying to figure out why this is happening. Even starting up bash and running phpunit triggers the issue.

sebastiansulinski's avatar

Did you by any chance run php artisan config:cache? If so - try to clear it php artisan config:clear and then run your tests again.

13 likes
rvanbaalen's avatar

Came here to confirm that this was in fact the solution.

Tried removing Oh My Zsh shell as well but that didn't do anything. artisan config:clear did the trick!

jago86's avatar

That was the solution. Thanks, i don't know when I ran config:cache, but that was the problem.

arbexmb's avatar

I am having the exact same problem @shaneturner. No idea why! Anyone got a solution for this problem or it remains a mystery?

I even tried to add force="true" to APP_ENV on phpunit.xml, but had no success...

ShaneTurner's avatar

For me, removing and reinstalling ZSH fixed the issue.

Must have been system variables conflicting with local project ones. Almost a year ago now, so I don't remember the details.

1 like
arbexmb's avatar

Thanks a lot for the answer. Got it here! :)

daveawb's avatar

This absolutely has to do with your system environment variables. First always check your shell echo $APP_ENV or the specific environment variable that is not being changed the way you'd wish. If the shell has the variable set, it will ALWAYS take precident no matter what you do with your .env or phpunit.xml files.

5 likes
jamesbellamy's avatar

To expand very slightly on @daveawb 's excellent point, you can use unset APP_ENV to clear the offending environment variable from your shell. Thereafter the tests will use the one set in phpunit.xml (or at least, they did for me).

1 like
connecteev's avatar

I am trying to ** read ** values from my .env file and access them in phpunit.xml Is there a way to do this? I do not want to define a new .env.testing file and have to maintain it separately, I just want to override 2 variables in my .env file.

I have tried:

        <server name="DB_CONNECTION" value="config('DB_CONNECTION_PHPUNIT')"/>
        <server name="DB_CONNECTION" value="env('DB_CONNECTION_PHPUNIT')"/>

phpunit errors out with:

4) Tests\Feature\Api\PostsApiTest::non_authenticated_users_cannot_access_the_following_endpoints_for_the_posts_api
InvalidArgumentException: Database connection [env('DB_CONNECTION_PHPUNIT')] not configured.

Any way to do this?

kirt's avatar

php artisan config:clear worked for me. Had already tried config:cache and cache:clear but seems they weren't enough!

jjudge's avatar

Had the same problem after upgrading to Laravel 8, phpunit 9,5. Checked the usualy suspects: phpunit.xml was being read, each env setting had the force="true"attribute, config was not being cached, however, the environment variables were set pointing to the MySQL database (that I did NOT want destroyed by the tests).

Then I found this report: https://www.gitmemory.com/issue/sebastianbergmann/phpunit/4540/745359854

I am running the tests in a comtainer, as will a growing number of people. In summary:

  • Running PHPunit 9.5
  • Running in a docker container
  • phpunit.xml can NOT override local environment variables, so the tests never switched to the sqlite database, and destroyed my staging database.

I'll post a fix for my situation, as soon as I find one. It may be simply that local environment variables must be reset, which does not feel safe.

This rough-and-ready check in trait CreateApplication will hopefully help protect against this, at least while using sqlite for feature tests.

    public function createApplication()
    {
        ...

        $app->make(Kernel::class)->bootstrap();

        if (config('database.default') === 'mysql') {
            throw new RuntimeException('Attempting to run tests against the mysql database; aborting');
        }
        ...
    }

I haven't got to the bottom of why Docker is important in this.

Some further research:

In a test, getenv('DB_CONNECTION') returns the environment value set in phpunit.xml, "sqlite". The getenv() function is a part of PHP, and that looks like phpunit is correctly overriding the env var. I believe phpunit does this by setting the appropriate superglobals.

However, env('DB_CONNECTION') ignores what phpunit has set, and goes back to the shell environment value, "mysql". The env() function is provided by Laravel. This behaviour changed for me between Laravel 7 and 8. I'm guessing Laravel is going somewhere other than the superglobals to get those values, or maybe the order of initialisation of Laravel and phpunit has changed?

I think this is a Laravel bug. It has been reported by a number of people, but summarily dismissed without referencing the details of the underlying issue. For example https://github.com/sebastianbergmann/phpunit/issues/4540 People are working around it by making sure environment variables are not set when testing. However, the behaviour in Laravel has changed, and that behaviour is losing people tine and databases.

Solution:

Switching from env to server swapped the two values around:

<env name="DB_CONNECTION" value="sqlite" force="true"/>

to

<server name="DB_CONNECTION" value="sqlite" force="true"/>

So in Laravel 8+ the Laravel config env() will look in the $_SERVER superglobal to get its environment variable values.

In Laravel to to 7, the Laravel config env() will look in the $_ENV supertglobal to get its environment variable values.

If you are not yet on Laravel 8, my recommendation for phpunit.xml, is to set both now, ready for a future upgrade. Both of these (and teh same for all other values):

<env name="DB_CONNECTION" value="sqlite" force="true"/>
<server name="DB_CONNECTION" value="sqlite" force="true"/>

You should not be using getenv() within your app, but using env() within teh config files instead. However, this change will help protect you from any getenv() values that have krept in.

9 likes
theferrett's avatar

@consil I have been searching the Internet for a solid four hours trying to figure this out and this is the only thread I've seen that a) explains things and b) worked. Thank you.

Adlas's avatar

I've just been investigating this issue after inheriting a Laravel project with an odd service provider that was throwing errors when running php artisan test.

After a bit of time I determined that phpunit.xml is used when the tests are being run but .env is used once at the beginning. And further if .env doesn't exist then the app environment (APP_ENV) defaults to "production".

So the logging of my tests shows one instance of the app being initialised in "production" and then lots of "testing".

My workaround for this issue is to run phpunit directly rather than through artisan. In my case it's for CI integration so I don't need the pretty CLI user interface. Or I'll set the environment variables on my CI server if I have to.

emanuti's avatar

check if your docker-compose.yml has env_file: .env declaration. It makes your container share .env application variables with container environment. So you need to remove this and maybe create another specific file to create environment variables into container. It was my case.

machi7's avatar

Thanks everyone who answered here. It lead me to properly debug which resulted to more relevant error message that also lead to more searching and finally finding the answer.

I cloned our laravel 10 project and among the team members I was the only having this issue. I'm using Laragon in my local machine. At first I was able to deduce that phpunit.xml wasn't being read. So thanks to @consil , when I changed to and did a dd('APP_ENV') it finally used the phpunit.xml variables. I also added force="true" there and got a different error. The error said sqlite driver was missing. Turned out my sqlite extension in php.ini was not enabled.

Please or to participate in this conversation.