0

I'm looking a solution to clear cache in Laravel, before starting all the tests (please note I mean ALL tests, not every single test):

    $this->artisan('cache:clear');
    $this->artisan('route:clear');
    $this->artisan('config:clear');

P.S. Laravel 9 and PHPUnit 9.5

Majesty
  • 2,097
  • 5
  • 24
  • 55
  • Honestly, there is no solution for you, just never run any `xxx:cache` before... I am not sure why you are having this issue, if it is for your team, for you, or who. It requires that you know what you are working with, and if it is for someone junior, just tell them to never run those commands locally, and if they did, just run each clear once and done... You can still use shell, that would be the best approach... – matiaslauriti Apr 13 '23 at 15:26
  • @matiaslauriti Hi, thanks for the advice! I came to an existing project where they run those lines before every single test from the `setUp` method. The documentation says it's needed only once before test run, so eventually I had to modify gitlab pipeline to run this from console instead. I thought there might be a way to do so using regular phpunit stuff. – Majesty Apr 14 '23 at 09:26
  • But you are not saying why you are having this issue, what is in your pipeline running cache? are you running `php artisan optimize` somewhere? are you literally running `php artisan config:cache` or `route:cache`, etc? When running tests, you should not care about that, it should not change anything, just asking out of curiosity because I have never had this issue nor saw someone having it – matiaslauriti Apr 14 '23 at 20:55

3 Answers3

0

Add

protected function setUp(): void
{
    parent::setUp();
    $this->artisan('cache:clear');
    $this->artisan('route:clear');
    $this->artisan('config:clear');
}

in tests/TestCase.php

Timur Rodya
  • 157
  • 1
  • 1
  • 6
0

You can do this by creating your own TestCase (or edit the original TestCase,php), and add these tasks to the createApplication method:

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\Artisan;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    public function createApplication()
    {
        $app = require __DIR__.'/../bootstrap/app.php';

        $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
        
        Artisan::call('cache:clear');
        Artisan::call('route:clear');
        Artisan::call('config:clear');

        return $app;
    }
}

Each test should extend this TestCase instead of Illuminate\Foundation\Testing\TestCase

You can also consider not to cache routes and configuration in your development environment. In your phpunit.xml you can also set the cache driver that is used during testing to a different one than that is used during development, e.g.:

<phpunit 
    ...>
    ...
    <php>
        ...
        <env name="CACHE_DRIVER" value="array"/>
        ...
    </php>
</phpunit>

That would drop the necessity to clear the caches before running your tests.

In this answer you can read more about configuration caching during testing. There you can also find a link to a GitHub issue that talks about clearing caches before running tests.

piscator
  • 8,028
  • 5
  • 23
  • 32
  • I mean before ALL tests, not before every test, sorry if wasn't clear enough – Majesty Apr 13 '23 at 09:22
  • I understand @Majesty, in that case you can add it to the `createApplication` method, please see updated answer. – piscator Apr 13 '23 at 09:35
  • I've just tested your approach by adding var_dump inside `createApplication` and it seems that this method is being called on every test case too – Majesty Apr 13 '23 at 10:19
  • I'm sorry for reading too fast. In that case you can just add a static variable `$cacheCleared`, only run the commands when it is `false` and set it to `true` after you run the commands. – piscator Apr 13 '23 at 10:27
  • Static variable won't work, each test will create an different app, and that's the same reason why `createApplication` doesn't worked. – Charlie Apr 13 '23 at 12:08
  • I is possible with a static variable: https://stackoverflow.com/a/56086498/4593376. Another solution would be to check if cache is already cleared. – piscator Apr 13 '23 at 13:21
  • @piscator I think you should read more carefully, not just copy someone's answered, the answer you posted said has a prerequisite that **if all of your tests are literally contained within a single class**, and in most cases your tests not be in single class. – Charlie Apr 14 '23 at 04:10
  • I've test static variables before, and that's why i said it won't work. – Charlie Apr 14 '23 at 04:11
  • I didn't copy anyone's answer, the answer linked explains you can add the static variable to a base class. Static variable will be shared. Strange it didn't work in your case, I've used it in many projects where it did work. Perhaps something is off, but I'm afraid we won't be able to resolve that in this discussion. – piscator Apr 14 '23 at 07:41
0

As I known, no such way to do this, because this is not the range of unit tests.

Unit tests designed to setting same environment for each tests, environment of all tests is not its responsibility.

But you can still work around by make a custom command to call config:clear and test.

1. Make a custom command.

php artisan make:command test

2. Edit your test command.

Default path will be app/Console/Commands/test.php.

...
/**
 * Execute the console command.
 */
public function handle()
{
    $this->call('cache:clear');
    $this->call('route:clear');
    $this->call('config:clear');
    $this->call('test');
}

3. Call unit tests by your own test command.

If you didn't change the default $signature, app:test will be the default command you just created.

Run php artisan app:test to call unit tests.

Charlie
  • 287
  • 11
  • Interesting approach, but how are you going to add command-line arguments when running your tests (for example filters, coverage, parallel)? That is impossible with this approach, or you have to add arguments each time to your custom console command, which is not very efficient. – piscator Apr 13 '23 at 10:35
  • @piscator Laravel does have ways to add arguments to custom command, you can read Laravel document to know how to do this. And this is not the issue this post asked. – Charlie Apr 13 '23 at 11:37
  • In my opinion, seems you didn't notice that `createApplication()` will call by each tests, I have the same issue before just like this post asked. – Charlie Apr 13 '23 at 11:38
  • In my case, I'm trying to create data for testing, before test start, I tried a lot of ways, even like you answered, by using `createApplication()` or the `setUp()`, there just no way to achieve what I really want. – Charlie Apr 13 '23 at 11:39
  • And I ended up with two solutions, one is custom command like the answer i posted, another way is using .env.testing, and create a testing database for unit test. – Charlie Apr 13 '23 at 11:40
  • You would have to add all the arguments manually to `$this->call('test');` – piscator Apr 13 '23 at 13:13