Search code examples
laraveltestinglaravel-5phpunitlaravel-artisan

Calling PHPUnit from Artisan command will ignore the XML File


I have what I think is an uncommon issue but I'll try to explain as clear as I can. I have created a simple artisan command that does this

 /**
 * Execute the console command.
 */
public function handle()
{
    $this->info("==> Cleaning up reports and docs...");

    $command = new Process("rm -f tests/docs/* && rm -rf test/reports/*");
    $command->run();

    $this->warn("==> Reports and docs are clean");

    $this->info("==> Executing Tests Suite...");
    $command = new Process("vendor/bin/phpunit --coverage-html tests/reports --testdox-html tests/docs/reports.html -v --debug");
    $command->run();
    $this->info($command->getIncrementalOutput());

    $this->warn("==> report generated >> test/reports. Documentation generated >> test/docs/reports.html");
}

This could seems kinda odd but it is actually pretty useful, it launch the PHPUnit with the coverage support and other stuff. The problem is that if I run this command like php artisan ludo237:full-test it will completely ignore the phpunit.xml in fact it will display and error saying that the MySQL database does not exists, even though I've set the sqlite connection inside my phpunit.xml speaking of which you can clearly see that is correct:

<?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="Application Test Suite">
            <directory suffix="Test.php">./tests</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="APP_DEBUG" value="true"/>
        <env name="APP_URL" value="http://localhost:8000"/>
        <env name="DB_CONNECTION" value="sqlite"/>
        <env name="DB_DATABASE" value=":memory:" />
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="MAIL_DRIVER" value="log"/>
        <env name="MAIL_PRETEND" value="true"/>
    </php>
</phpunit>

I know that I can simply create a bash alias for that command line, in fact this is my current hot fix, but at this point I'm just curious to understand why when I launch the phpunit command from the artisan command it ignores the XML file.

Does anyone have a clue about this? Thank you!


Solution

  • It took me really a lot to debug this, but in the end I found why it is not working.

    First of all, let me clarify that is nothing wrong with your code, even there is nothing wrong with the Process class, you will get the same behavior even by using native exec function.

    Second, the phpunit.xml file is totally being read, no issues at all.

    Said that, the real issue resides, on PHPUnit that doesn't allow you to re-define ( or override ) any env variable, because there is a check that prevents that.

    This is because Laravel is not parsing the phpunit.xml file itself, and in the moment you're calling it, it's already too late and the environment variables are defined, either via putenv, $_SERVER and/or $_ENV.

    Because of this, I created an Issue on PHPUnit, which even in latest versions ( as of today ), this issue persist, even if this was already asked in the past.

    Unfortunately I have no solution yet for you, but let's cross our fingers and let's wait for PHPUnit to add the proposed force attribute :)

    Best regards, Julian