Laravel: Database tables deleted after running phpunit test
Asked Answered
O

6

11

Every time I run a test all my database tables (except for the migrations table) are being deleted and I have to run the migrations again. For instance, if I have the following tables:

migrations
users
tableA
tableB

after running:

phpunit --filter user_can_view_a_record ViewRecordTest tests/Feature/ViewRecordTest.php

my tables are deleted and I end up with just the migrations table.

I'm using MySQL as database and according to the configuration I have set up the tests are being running in memory:

database.php

'connections' => [

        'sqlite' => [
            'driver' => 'sqlite',
            //'database' => env('DB_DATABASE', database_path('database.sqlite')),
            'database' => ':memory:',
            'prefix' => '',
        ],

        'mysql' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => false,
            'engine' => null,
            'sticky' => true
        ],
]

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>

Thanks

Octahedron answered 3/9, 2018 at 18:12 Comment(11)
What Laravel version is this?Sartre
Laravel Version: 5.5Octahedron
Can't you upgrade to 5.6? or better yet to master? (5.7 will be released really soon). Do you use Illuminate\Foundation\Testing\RefreshDatabase;? as documentation states? laravel.com/docs/5.5/…Sartre
Also write a test that just displays current environment is it testing? I think phpunit.xml is not being used. You can do that via dd(app()->environment());.Sartre
I'm sorry, I just checked. It's not 5.5 but 5.6. I ran dd(app()->environment()); as you suggested and I'm getting "local"Octahedron
So thats why. When you run a test its using your real database (or mysql connection) instead of sqlite one. Are you in your app root when you run phpunit command? I personally use this alias phpunit=vendor/bin/phpunit and it uses phpunit.xml by default.Sartre
So how can I make it use sqlite? When executing I'm located in my project's root where the .xml file lives. I tried specifying the xml file by running ./vendor/bin/phpunit --configuration phpunit.xml --filter user_can_view_a_record ViewRecordTest tests/Feature/ViewRecordTest.php but I'm getting the same resultOctahedron
Are you running this in Docker by any chance? Anyway you need to figure why the xml is not respected by phpunit. Google around...Sartre
Will do thanks. Not using DockerOctahedron
I got it; do not cache config during development... so run php artisan cache:clear. Good Luck! :)Sartre
Obviously php artisan config:clear...Sartre
S
11

the solution of Michael Ameyaw worked well for me in PHPStorm ! thank you.
I wanted to mention that it could be also a cache problem, so try this:

php artisan config:clear
Several answered 3/1, 2019 at 11:50 Comment(1)
Can you please refer to the solution of Michael Ameyaw ? Where it is?Dhammapada
P
2

In general you should have separated database with same table structure like staging env. It is normal behavior of unit tests (I mean deleting of tables). Typical flow for testing is (for each test execution):

  1. delete all tables.
  2. Run all migrations (create tables, alter tables, etc).
  3. Load fixtures
  4. Execute tests on fresh database.

Imagine situation, that one of tests change data in for example user table (change email or first name etc) if phpunit don't drop all data next tests will work with incorrect data ( changed by another test). You can check laravel main documentation for more details.

Psittacine answered 3/9, 2018 at 18:38 Comment(3)
Thanks, I know that and that's why there are two different databases (as mentioned in the question) one is mysql for my persistent data and the other one is sqlite for testing (non-persistent data)Octahedron
Ok, then I can't sort out your main question. You need to run migrations automatically each test running?Psittacine
You are welcome. Did you check documentation link that I post in answer? Is it helpful for you?Psittacine
G
1

I got a solution, if you are using phpStorm look for test framework.

File >> settings >> File & Framework >> Test Framework.

Set a default configuration file to phpunit.xml in your root folder

Gigigigli answered 3/11, 2018 at 11:13 Comment(0)
N
0

As mentioned above, this is most likely a problem with Laravel using cached database credentials which point to your local/dev database and not that for your testing.

While running php artisan config:clear solves the problem, there are chances that the problem may occur again in the future.

A permanent solution is to edit your tests\CreatesApplication class like below:

<?php

namespace Tests;

use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;

trait CreatesApplication
{
    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication()
    {
        $app = require __DIR__.'/../bootstrap/app.php';

        $app->make(Kernel::class)->bootstrap();

        $this->clearCache();

        return $app;
    }

    private function clearCache(): void
    {
        Artisan::call('cache:clear');
    }
}

This ensures that your cache is clear before the tests are run.

Got insights for this response from my experience making tweaks to this response: https://laracasts.com/discuss/channels/laravel/phpunit-is-deleting-my-database?page=1&replyId=700380

Nucleolated answered 6/9, 2021 at 5:24 Comment(0)
U
0

I had the same issue and this might be helpful for someone. I was working on 2 different Lumen projects both interacting with the same database.

The issue was solved having the same migrations structure on both projects!

The migration files of one project was missing some columns and for some reason had the same behavior of deleting all the database tables after running phpunit.

Undies answered 27/10, 2021 at 16:37 Comment(0)
B
0

I had this problem with all my database tables getting deleted when one test ran, and eventually resolved it by removing the RefreshDatabase trait which was not needed for the test.

use Illuminate\Foundation\Testing\RefreshDatabase; // Remove this
use Tests\TestCase;

class MyTest extends TestCase
{
    use RefreshDatabase; // Remove this
}
Browse answered 9/8 at 22:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.