Posts | About

Laravel Feature Tests Alternative MySQL Config

May 21, 2020 by Areg Sarkissian

In the previous two blog posts Laravel Feature Tests With MySQL In Docker and Laravel Run Parallel Tests With MySQL In Docker I showed you feature test configurations for running Laravel feature tests with a MySQL test database running in docker. The first post covered configurations for running tests normally the other for running tests in parallel.

In this post I will outline an alternative testing configuration that can be used for either running tests normally or in parallel without having to create a .env.testing file as was required when running tests in parallel.

See either of the blog posts mentioned above to setup your docker-compose configuration file to run a MySQL test database server.

Adding a test database connection to config/database.php

First we need to add our test database configuration to the config/database.phpfile by copying the default mysql connection configuration in config/database.php and renaming the copy to test-mysql. Then we need to make the port setting of the test-mysql connection to use a TEST_DB_PORT environment variable setting instead of the original DB_PORT setting.

The result of the change in the config/database.php file is shown here:

# the default database connection setting
'default' => env('DB_CONNECTION', 'mysql'),

'connections' => [
# the default database connection
'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '8001'),
            'database' => env('DB_DATABASE', 'radar'),
            'username' => env('DB_USERNAME', 'radar'),
            'password' => env('DB_PASSWORD', 'radar'),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],
#the test database connection copy of the 'mysql' connection
'test-mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            # the changed port setting that uses TEST_DB_PORT instead of DB_PORT
            'port' => env('TEST_DB_PORT'),
            'database' => env('DB_DATABASE', 'radar'),
            'username' => env('DB_USERNAME', 'radar'),
            'password' => env('DB_PASSWORD', 'radar'),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],
]

Since we added the TEST_DB_PORT environment variable to the configuration file, we need to add it to the .env file. Then we need to set its value to the local host mapped port value of the test MySQL database server port specified the docker-compose.yml file.

So if we have the following mysqltest test database configuration in docker-compose.yml:

    mysqltest:
      image: mysql:8.0
      container_name: radar-mysql-test
      environment:
        - MYSQL_ROOT_PASSWORD="${DB_PASSWORD}"
        - MYSQL_DATABASE="${DB_DATABASE}"
        - MYSQL_USER="${DB_USERNAME}"
        - MYSQL_PASSWORD="${DB_PASSWORD}"
      ports:
        # port mapping
        - "8011:3306"

Then we need to add the following environment variable to the .env file:

TEST_DB_PORT=8011

Overriding DB_CONNECTION in phpunit.xml

In order to run our tests against the test database we need to override the DB_CONNECTION setting in the .env file and set it to test-mysql so that the default database connection uses the test-mysql in the config/database.php file.

By overriding the DB_CONNECTION we are changing the default database connection used to run the migrations and tests to test-mysql and since the test-mysql connection uses the TEST_DB_PORT setting, the tests will connect to the test database running in docker.

In the phpunit.xml file we can override the DB_CONNECTION value in by adding the following setting inside the php element in the file:

<server name="DB_CONNECTION" value="test-mysql"/>

If we are not running our tests in parallel then this is the only setting we need to override to run our tests. We just need to make sure that we are also using the RefreshDatabase trait in our test classes.

If we are running our tests in parallel then we need to also configure our database migrations to run against the test database server as shown in the next section.

Connecting database migrations to test database for parallel tests

As mentioned in the parallel testing blog post, we need to run migrations manually on the command line before running the tests instead of using the the RefreshDatabase trait.

When running the migrations manually we need to specify which database the migrations run against in the migration command.

We can specify the database that migrations should use by setting the --database option of the artisan migrate command to the value of the DB_CONNECTION setting in the phpunit.xml file as shown below:

php artisan migrate --database=test-mysql

As noted before, since the specified test-mysql connection uses the TEST_DB_PORT setting, the migrations will run against the test database running in docker.

Using this migration command we can follow the instructions in Laravel Run Parallel Tests With MySQL In Docker to run our phpunit tests in parallel.