/ tests / RefreshTestDatabase.php
RefreshTestDatabase.php
 1  <?php
 2  namespace Tests;
 3  
 4  use Database\Seeders\TestDatabaseSeeder;
 5  use Illuminate\Contracts\Console\Kernel;
 6  use Illuminate\Foundation\Testing\DatabaseTransactions;
 7  use Illuminate\Foundation\Testing\RefreshDatabaseState;
 8  use Symfony\Component\Finder\Finder;
 9  
10  trait RefreshTestDatabase
11  {
12      use DatabaseTransactions;
13  
14      protected function refreshTestDatabase()
15      {
16          if (! RefreshDatabaseState::$migrated) {
17              $this->runMigrationsIfNecessary();
18  
19              $this->app[Kernel::class]->setArtisan(null);
20  
21              RefreshDatabaseState::$migrated = true;
22          }
23  
24          $this->beginDatabaseTransaction();
25      }
26  
27      protected function runMigrationsIfNecessary(): void
28      {
29          if (false === $this->identicalChecksum()) {
30              $this->createChecksum();
31              $this->artisan('migrate:fresh');
32              $this->seed([TestDatabaseSeeder::class]);
33          }
34      }
35  
36      protected function calculateChecksum(): string
37      {
38          $files = Finder::create()
39              ->files()
40              ->exclude([
41                  'factories',
42                  'seeders',
43              ])
44              ->in(database_path())
45              ->ignoreDotFiles(true)
46              ->ignoreVCS(true)
47              ->getIterator();
48  
49          $files = array_keys(iterator_to_array($files));
50  
51          $checksum = collect($files)->map(fn($file) => md5_file($file))->implode('');
52  
53          return md5($checksum);
54      }
55  
56      protected function checksumFilePath(): string
57      {
58          return base_path('.phpunit.database.checksum');
59      }
60  
61      protected function createChecksum(): void
62      {
63          file_put_contents($this->checksumFilePath(), $this->calculateChecksum());
64      }
65  
66      protected function checksumFileContents(): bool|string
67      {
68          return file_get_contents($this->checksumFilePath());
69      }
70  
71      protected function isChecksumExists(): bool
72      {
73          return file_exists($this->checksumFilePath());
74      }
75  
76      protected function identicalChecksum(): bool
77      {
78          if (false === $this->isChecksumExists()) {
79              return false;
80          }
81  
82          if ($this->checksumFileContents() === $this->calculateChecksum()) {
83              return true;
84          }
85  
86          return false;
87      }
88  }