datapult's avatar

Laravel not using the test DB connection

Hi there

I want Laravel to run tests in my test DB connection but inside a test dd(config('database.default'), env('DB_CONNECTION')); gives:

"mysql"
"mysql"

My config/database.php:

<?php

use Illuminate\Database\DBAL\TimestampType;

return [
    'default' => env('DB_CONNECTION', 'mysql'),
    'connections' => [
        'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', 'mysql'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', 'forge'),
            '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'),
            ]) : [],
        ],

        'testing' => [
            'driver' => 'mysql',
            'host' => 'test_mysql', // see docker-compose.dev.yml
            'port' => '3307', // see docker-compose.dev.yml
            'database' => 'TEST_DB', // see docker-compose.dev.yml
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', 'forge'),
            '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'),
            ]) : [],
        ],

My 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"
         stopOnFailure="true"
         stopOnError="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>
    <env name="APP_ENV" value="testing" force="true" />
    <env name="DB_CONNECTION" value="testing" force="true" />
    <env name="DB_HOST" value="test_mysql" force="true" />
    <env name="DB_PORT" value="3307" force="true" />
    <env name="DB_DATABASE" value="TEST_DB" force="true" />
    <env name="DB_USERNAME" value="forge" force="true" />
    <env name="DB_PASSWORD" value="forge" force="true" />
    <env name="BCRYPT_ROUNDS" value="4"/>
    <env name="CACHE_DRIVER" value="redis"/>
    <env name="MAIL_MAILER" value="array"/>
    <env name="QUEUE_CONNECTION" value="sync"/>
    <env name="SESSION_DRIVER" value="array"/>
    <env name="TELESCOPE_ENABLED" value="false"/>
  </php>
</phpunit>

My .env.testing

APP_KEY=[SOME_KEY]
APP_ENV=testing
CACHE_DRIVER=redis
APP_DEBUG=true
DB_CONNECTION=testing

The setup is containerized:

version: "3.9"
services:

  backend:
    container_name: backend
    image: laravel
    build:
      context: ./../
      dockerfile: ./docker/Dockerfile
    depends_on:
      - mysql
    extra_hosts:
      - "host.docker.internal:host-gateway"
    ports:
      - "80:80"
    volumes:
      - ./../:/var/www/html
      - anonymousvolume1:/var/www/html/vendor
      - /var/www/html/node_modules
    env_file:
      - ./../.env
    environment:
      - CONTAINER_ROLE=app
      - APP_DEBUG=true
    networks:
      - pms-network

  mysql:
    container_name: mysql
    image: mariadb:10.6.12
    ports:
      - "3306:3306"
    volumes:
      - ./../mysql/:/docker-entrypoint-initdb.d
    environment:
      MYSQL_DATABASE: forge
      MYSQL_ROOT_PASSWORD: forge
      MYSQL_USER: forge
      MYSQL_PASSWORD: forge
    networks:
      - pms-network

  test_mysql:
    container_name: test_mysql
    image: mariadb:10.6.12
    ports:
      - "3307:3306"
    volumes:
      - ./../mysql/:/docker-entrypoint-initdb.d
    environment:
      MYSQL_DATABASE: TEST_DB
      MYSQL_ROOT_PASSWORD: forge
      MYSQL_USER: forge
      MYSQL_PASSWORD: forge
    networks:
      - pms-network

networks:
  pms-network:
    driver: bridge
volumes:
  anonymousvolume1:
    driver: local
0 likes
4 replies
LaryAI's avatar
Level 58

The issue seems to be with the configuration of the test database connection. The DB_CONNECTION value in the .env.testing file should be set to testing instead of testing_db.

To fix this issue, you can update the .env.testing file as follows:

APP_KEY=[SOME_KEY]
APP_ENV=testing
CACHE_DRIVER=redis
DB_CONNECTION=testing
APP_DEBUG=true

Make sure to save the changes and then run your tests again. The dd(config('database.default'), env('DB_CONNECTION')); should now output testing for both values.

Let me know if you have any further questions!

datapult's avatar

The value of DB_CONNECTION in .env.testing is already testing?

datapult's avatar

I had a fundamental misconception of port mapping. Here is what the above is doing: In the docker-compose.yml, the port is mapped as 3307:3306 for the testdb service. This means that outside of Docker, the service listens on port 3307, but inside Docker (i.e., between Docker containers), it listens on port 3306.

tisuchi's avatar

@datapult

I had a fundamental misconception of port mapping. Here is what the above is doing: In the docker-compose.yml, the port is mapped as 3307:3306 for the testdb service. This means that outside of Docker, the service listens on port 3307, but inside Docker (i.e., between Docker containers), it listens on port 3306.

Correct.

Please or to participate in this conversation.