kernel = $this->createMock(KernelInterface::class); $this->entityManager = $this->createMock(EntityManagerInterface::class); $this->mailer = $this->createMock(Mailer::class); $this->databaseDumper = $this->createMock(DatabaseDumper::class); $this->zipArchiver = $this->createMock(ZipArchiver::class); } public function testExecuteSuccess() { // 1. Setup Data $projectDir = sys_get_temp_dir() . '/backup_test_' . uniqid(); mkdir($projectDir . '/sauvegarde', 0777, true); $this->kernel->method('getProjectDir')->willReturn($projectDir); // 2. Expectations // EntityManager $this->entityManager->expects($this->once())->method('persist')->with($this->isInstanceOf(Backup::class)); $this->entityManager->expects($this->atLeast(2))->method('flush'); // Once at start, once at end // Cleanup expectations // Mocking Query class which might be final. If so, we'll see an error. // But commonly in Doctrine mocks, we have to deal with this. $query = $this->createMock(Query::class); $query->method('setParameter')->willReturnSelf(); $query->method('execute'); $this->entityManager->method('createQuery')->willReturn($query); // Database Dumper $this->databaseDumper->expects($this->once()) ->method('dump') ->with($this->anything(), $this->stringEndsWith('temp_db.sql')); // Zip Archiver $this->zipArchiver->expects($this->once()) ->method('createArchive') ->willReturnCallback(function($zipPath, $sqlPath, $dirs) { // Create a dummy zip file so filesize() works touch($zipPath); }); // Mailer $this->mailer->expects($this->once()) ->method('send') ->with( 'notification@siteconseil.fr', 'Intranet Ludievent', $this->stringContains('✅ Sauvegarde'), 'mails/backup_notification.twig', $this->callback(function($context) { return isset($context['backup']) && $context['backup']->getStatus() === 'SUCCESS'; }) ); // 3. Execution $command = new BackupCommand( $this->kernel, $this->entityManager, $this->mailer, $this->databaseDumper, $this->zipArchiver ); $application = new Application(); $application->add($command); $commandTester = new CommandTester($application->find('app:backup')); $commandTester->execute([]); // 4. Assertions $output = $commandTester->getDisplay(); $this->assertStringContainsString('Sauvegarde réussie', $output); // Cleanup $this->removeDirectory($projectDir); } public function testExecuteFailure() { // 1. Setup Data $projectDir = sys_get_temp_dir() . '/backup_test_fail_' . uniqid(); mkdir($projectDir . '/sauvegarde', 0777, true); $this->kernel->method('getProjectDir')->willReturn($projectDir); // 2. Expectations - Fail at Dump $this->databaseDumper->expects($this->once()) ->method('dump') ->willThrowException(new \Exception("Simulated Dump Error")); // Mailer - Should send Error notification $this->mailer->expects($this->once()) ->method('send') ->with( 'notification@siteconseil.fr', 'Intranet Ludievent', $this->stringContains('❌ Sauvegarde'), 'mails/backup_notification.twig', $this->callback(function($context) { return isset($context['backup']) && $context['backup']->getStatus() === 'ERROR' && $context['backup']->getErrorMessage() === 'Simulated Dump Error'; }) ); // Cleanup expectations $query = $this->createMock(Query::class); $query->method('setParameter')->willReturnSelf(); $query->method('execute'); $this->entityManager->method('createQuery')->willReturn($query); // 3. Execution $command = new BackupCommand( $this->kernel, $this->entityManager, $this->mailer, $this->databaseDumper, $this->zipArchiver ); $application = new Application(); $application->add($command); $commandTester = new CommandTester($application->find('app:backup')); $commandTester->execute([]); // 4. Assertions $output = $commandTester->getDisplay(); $this->assertStringContainsString('Échec : Simulated Dump Error', $output); // Cleanup $this->removeDirectory($projectDir); } private function removeDirectory($dir) { if (!is_dir($dir)) return; $files = array_diff(scandir($dir), array('.','..')); foreach ($files as $file) { (is_dir("$dir/$file")) ? $this->removeDirectory("$dir/$file") : unlink("$dir/$file"); } rmdir($dir); } }