Laravel/Phpunit: is it possible to force DB connection via terminal? - laravel

I have a Laravel project.
I want test it on my develop machine + Travis/Scrutinizer with SQLite, plus I want test on another machine with MySQL.
This is my PHPUnit file that works like a charme
<?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>
<logging>
<!-- and this is where your report will be written -->
<log type="coverage-clover" target="./logs/clover.xml"/>
</logging>
<php>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="MAIL_DRIVER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
</php>
</phpunit>
I'm asking: is there a possibility to launch on a linux shell command a similar command (pseudocode, of course):
./vendor/bin/phpunit --db_connection=mysql
?

It is not possible to edit the phpunit.xml file dynamically from the command line by default, but you can set the DB_CONNECTION environment variable (and other variables) like this:
DB_CONNECTION=mysql ./vendor/bin/phpunit
You can view more options for setting environment variables in this answer.

Related

Why would PHPunit ignore .env.testing?

I have a newly installed Laravel 6.4 application running and now trying to get tests working with PHPunit. I want to make configuration changes in .env.testing but any changes in here seem to be ignored.
phpunit.xml contains this:
<php>
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<server name="MAIL_DRIVER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
</php>
And I have also have included $app->loadEnvironmentFrom('/var/www/api/.env.testing'); into tests/CreatesApplication.php createApplication() method. All paths are correct so I don't understand why it is not reading the file. I've found similar mentions of this issue when googling but none have helped me resolve the issue.
I am running PHPunit with the command vendor/bin/phpunit. Does anyone have suggestions on what I can try?

How to set different MySQL database for testing?

I have installed a fresh Laravel project. I tried to set different database for PHPUnit testing, by adding "DB_DATABASE" And adding "use DatabaseMigrations" trait inside the test..
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<server name="MAIL_DRIVER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="DB_DATABASE" value="test_homestead" />
But I am getting this error:
1) Tests\Feature\ViewArticleTest::user_can_view_an_article
Illuminate\Database\QueryException: SQLSTATE[HY000] [1049] Unknown database 'test_homestead' (SQL: SHOW FULL TABLES WHERE table_type = 'BASE TABLE')`
The error indicates that your test_homestead isn't available in your MySQL.
You should create a database by perform CREATE DATABASE test_homestead; in MySQL.
Or
Change the value in <server name="DB_DATABASE" value="test_homestead" /> to your desirable existing database name.

Is there a way of mocking an API request by default if you are in a test environment using Laravel?

I have an API method that is called by clicking a buttom in a form and inside that API method there is a request to another API of another project using guzzle. That works fine.
My problem is I'm doing behat tests and I want to test my API method, but I need to mock the request to the external API (because I don't need to test it). Is there any way Laravel detects if I am in a test environment and mock the request and if I'm in a normal environment leave it without mock?
There should be a file in your project called phpunit.xml and you can set the APP_ENV there.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
...
processIsolation="false"
stopOnFailure="false">
<testsuites>
...
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app</directory>
</whitelist>
</filter>
<php>
<!-- HERE -->
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
</php>
Then you can use whatever logic you like with if(env('APP_ENV') == 'testing')

Failure to set APP_ENV to 'testing' for unit testing in Laravel 5.5

I am using Laravel 5.5, phpunit 6.5.5 on Homestead-7 (I think).
I am trying this tutorial: https://laravel-news.com/your-first-laravel-application (And this should tell you a lot about my experience with the framework)
Testing fails (due to TokenMismatchException) and I have managed to track down the root cause to the APP_ENV variable being set to local, although I've tried many ways of setting it to testing.
At the end, what allowed me to overcome the problem was to set the variable like this:
APP_ENV=testing vendor/bin/phpunit
Then, the tests completed successfully.
My question is, what am I doing wrong? The above hack is obviously not the best way to do it. There must be a way to properly do this.
Update
Contents of 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="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
<testsuite name="Unit">
<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"/>
<env name="DB_DATABASE" value=":memory:"/>
</php>
</phpunit>
Thank you in advance for your time.
From the Laravel docs:
When running tests via phpunit, Laravel will automatically set the configuration environment to testing because of the environment variables defined in the phpunit.xml file.
...so I would bet that your phpunit.xml file is missing or misconfigured. It should be in your project's root directory and should contain the following:
<php>
<env name="APP_ENV" value="testing"/>
...
</php>
If you do have a phpunit.xml file in the right place and it does contain the part above, and it's still not working, then try clearing your config cache:
php artisan config:clear
If that still doesn't fix it, then I'd check for something odd with the phpunit.xml file, such as being misnamed or containing a syntax error.
And here's a link to the original phpunit.xml file, to help you restore it if needed.
I managed to find the problem with my system. In my homestead box, I had included in Homestead.yaml setting of global environment variable APP_ENV:
variables:
- key: APP_ENV
- value: local
This was provided as an example in the instructions for Homestead set up. I followed that without realising what I was doing.
Setting again the variable through .env or phpunit.xml just did not work. I removed the definition from Homestead.yaml and it works as I would have expected.

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!
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

Resources