Back to Course |
Testing in Laravel 9 For Beginners: PHPUnit, Pest, TDD

Database Configuration: RefreshDatabase, Phpunit.xml and .env.testing

As you saw in the previous lesson, we interact with the database, which creates actual data in an actual database, which is wrong because tests should be run separately. Kinda like simulating the database. We shouldn't interact with live databases at all. For that, we need to configure on which database our tests would run.


When creating a new Laravel project, you can choose the testing framework. But the configuration is made in the phpunit.xml file for both frameworks.

And the database configuration is in two variables, which are commented out by default.

phpunit.xml:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory suffix="Test.php">./tests/Feature</directory>
</testsuite>
</testsuites>
<php>
<server name="APP_ENV" value="testing"/>
<server name="BCRYPT_ROUNDS" value="4"/>
<server name="CACHE_DRIVER" value="array"/>
<!-- <server name="DB_CONNECTION" value="sqlite"/> -->
<!-- <server name="DB_DATABASE" value=":memory:"/> -->
<server name="MAIL_MAILER" value="array"/>
<server name="QUEUE_CONNECTION" value="sync"/>
<server name="SESSION_DRIVER" value="array"/>
<server name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>

You need to specify the connection and the database where your tests should be run. You can check what connections are available in the config/database.php. For example, SQLite, mysql.

In most cases, running tests using the SQLite connection and memory as the database is pretty safe. You wouldn't need to create a separate database.

The Exception to using SQLite is if you use specific MySQL functions that SQLite doesn't support. Then, you will have errors.

Uncomment those two lines in the phpunit.xml and re-run the tests. We get an error no such table: products.

no table error

And of course. We specified a new connection and database but have not run the migrations. So, we need to run migrations on that database whenever we run the test. For that, Laravel has a trait, RefreshDatabase. This trait will re-run migration every time this test is run.

tests/Feature/ProductsTest.php:

use Illuminate\Foundation\Testing\RefreshDatabase;
 
class ProductsTest extends TestCase
{
use RefreshDatabase;
 
// ...
}

Here, you need to be careful not to accidentally launch tests on a live database because this will refresh the database. Now, if we re-run the tests, we see all are green.

tests sqlite green

And if you look in the products table on your live database, you will see that no new records were added.


In addition to phpunit.xml, there is another way to configure env variables. Similar to what you do in .env, you can create a separate .env.testing.

Comment out the DB configuration in the phpunit.xml file. Create a new file .env.testing with the same content as in .env.

Now we can change the DB connection and database in the .env.testing. When the tests are run, the DB connection settings will be taken from .env.testing.

.env.testing:

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:Oo7mTQpSW00WmjWs1kJVjqFZw/oQVENUxyhuyLCQgfk=
APP_DEBUG=true
APP_URL=http://localhost
 
LOG_CHANNEL=stack
LOG_LEVEL=debug
 
DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=:memory:
DB_USERNAME=root
DB_PASSWORD=
 
// ...

It's your preference whether to use phpunit.xml or .env.testing.