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 }