db = new PDO('sqlite::memory:', options: [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); $this->db->exec('CREATE TABLE notification_dispatches (id INTEGER PRIMARY KEY AUTOINCREMENT, recipient TEXT NOT NULL, subject TEXT NOT NULL, template TEXT NOT NULL, status TEXT NOT NULL, notification_key TEXT DEFAULT NULL, error_message TEXT DEFAULT NULL, created_at TEXT NOT NULL, sent_at TEXT DEFAULT NULL)'); $this->mailer = $this->createMock(MailServiceInterface::class); $this->service = new NotificationApplicationService($this->mailer, new PdoNotificationDispatchRepository($this->db)); } public function testSendTemplateRecordsSuccessfulDispatch(): void { $this->mailer->expects($this->once()) ->method('send') ->with('user@example.test', 'Sujet', '@Identity/emails/password-reset.twig', ['name' => 'Ada']); $this->service->sendTemplate('user@example.test', 'Sujet', '@Identity/emails/password-reset.twig', ['name' => 'Ada'], 'password-reset'); $history = $this->service->recent(); self::assertCount(1, $history); self::assertSame('sent', $history[0]->status); self::assertSame('password-reset', $history[0]->notificationKey); } public function testFailureIsRecordedAndRethrown(): void { $this->mailer->expects($this->once()) ->method('send') ->willThrowException(new \RuntimeException('SMTP indisponible')); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('SMTP indisponible'); try { $this->service->sendTemplate('user@example.test', 'Sujet', '@Identity/emails/password-reset.twig'); } finally { $history = $this->service->recent(); self::assertCount(1, $history); self::assertSame('failed', $history[0]->status); self::assertSame('SMTP indisponible', $history[0]->errorMessage); } } }