Files
Gnuboard7/tests/Unit/Repositories/MailSendLogRepositoryTest.php
T
2026-04-01 10:30:52 +09:00

293 lines
9.4 KiB
PHP

<?php
namespace Tests\Unit\Repositories;
use App\Enums\ExtensionOwnerType;
use App\Enums\MailSendStatus;
use App\Models\MailSendLog;
use App\Repositories\MailSendLogRepository;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
use Tests\TestCase;
/**
* MailSendLogRepository 테스트
*
* 메일 발송 이력 리포지토리의 필터링, 페이지네이션, 통계 조회를 검증합니다.
*/
class MailSendLogRepositoryTest extends TestCase
{
use RefreshDatabase;
private MailSendLogRepository $repository;
protected function setUp(): void
{
parent::setUp();
$this->repository = app(MailSendLogRepository::class);
}
// ========================================================================
// create
// ========================================================================
/**
* 발송 이력을 생성합니다
*/
public function test_create_returns_mail_send_log(): void
{
$data = [
'recipient_email' => 'test@example.com',
'recipient_name' => 'Test User',
'subject' => 'Test Subject',
'template_type' => 'welcome',
'extension_type' => ExtensionOwnerType::Core,
'extension_identifier' => 'core',
'source' => 'notification',
'status' => 'sent',
'sent_at' => now(),
];
$log = $this->repository->create($data);
$this->assertInstanceOf(MailSendLog::class, $log);
$this->assertTrue($log->exists);
$this->assertEquals('test@example.com', $log->recipient_email);
$this->assertEquals('notification', $log->source);
$this->assertDatabaseHas('mail_send_logs', [
'recipient_email' => 'test@example.com',
'source' => 'notification',
]);
}
// ========================================================================
// getPaginated - 기본 동작
// ========================================================================
/**
* 필터 없이 전체 목록을 페이지네이션하여 반환
*/
public function test_get_paginated_returns_all_logs_without_filters(): void
{
MailSendLog::factory()->count(5)->create();
$result = $this->repository->getPaginated();
$this->assertCount(5, $result->items());
$this->assertEquals(5, $result->total());
}
/**
* 빈 결과를 올바르게 반환
*/
public function test_get_paginated_returns_empty_when_no_logs(): void
{
$result = $this->repository->getPaginated();
$this->assertCount(0, $result->items());
$this->assertEquals(0, $result->total());
}
/**
* sent_at 기준 최신순 정렬
*/
public function test_get_paginated_orders_by_sent_at_desc(): void
{
$older = MailSendLog::factory()->create(['sent_at' => now()->subDays(2)]);
$newer = MailSendLog::factory()->create(['sent_at' => now()]);
$result = $this->repository->getPaginated();
$items = $result->items();
$this->assertEquals($newer->id, $items[0]->id);
$this->assertEquals($older->id, $items[1]->id);
}
/**
* perPage 파라미터로 페이지 크기 제어
*/
public function test_get_paginated_respects_per_page(): void
{
MailSendLog::factory()->count(10)->create();
$result = $this->repository->getPaginated([], 3);
$this->assertCount(3, $result->items());
$this->assertEquals(10, $result->total());
}
// ========================================================================
// getPaginated - 필터
// ========================================================================
/**
* extension_type 필터
*/
public function test_get_paginated_filters_by_extension_type(): void
{
MailSendLog::factory()->forExtension(ExtensionOwnerType::Core, 'core')->count(3)->create();
MailSendLog::factory()->forExtension(ExtensionOwnerType::Module, 'sirsoft-ecommerce')->count(2)->create();
$result = $this->repository->getPaginated(['extension_type' => 'core']);
$this->assertCount(3, $result->items());
}
/**
* template_type 필터
*/
public function test_get_paginated_filters_by_template_type(): void
{
MailSendLog::factory()->withTemplateType('welcome')->count(2)->create();
MailSendLog::factory()->withTemplateType('password_reset')->count(3)->create();
$result = $this->repository->getPaginated(['template_type' => 'welcome']);
$this->assertCount(2, $result->items());
}
/**
* status 필터
*/
public function test_get_paginated_filters_by_status(): void
{
MailSendLog::factory()->count(4)->create(['status' => MailSendStatus::Sent->value]);
MailSendLog::factory()->failed()->count(2)->create();
$result = $this->repository->getPaginated(['status' => MailSendStatus::Failed->value]);
$this->assertCount(2, $result->items());
}
/**
* search 필터 - 이메일 검색
*/
public function test_get_paginated_search_matches_email(): void
{
MailSendLog::factory()->create(['recipient_email' => 'admin@example.com']);
MailSendLog::factory()->create(['recipient_email' => 'user@example.com']);
$result = $this->repository->getPaginated(['search' => 'example.com']);
$this->assertCount(1, $result->items());
$this->assertEquals('admin@example.com', $result->items()[0]->recipient_email);
}
/**
* search 필터 - 수신자 이름 검색
*/
public function test_get_paginated_search_matches_recipient_name(): void
{
MailSendLog::factory()->create(['recipient_name' => 'Kim Admin']);
MailSendLog::factory()->create(['recipient_name' => 'Lee User']);
$result = $this->repository->getPaginated(['search' => 'Kim']);
$this->assertCount(1, $result->items());
}
/**
* search 필터 - 제목 검색
*/
public function test_get_paginated_search_matches_subject(): void
{
MailSendLog::factory()->create(['subject' => '비밀번호 재설정 안내']);
MailSendLog::factory()->create(['subject' => '환영합니다']);
$result = $this->repository->getPaginated(['search' => '비밀번호']);
$this->assertCount(1, $result->items());
}
/**
* date_from 필터
*/
public function test_get_paginated_filters_by_date_from(): void
{
MailSendLog::factory()->create(['sent_at' => Carbon::parse('2026-01-01')]);
MailSendLog::factory()->create(['sent_at' => Carbon::parse('2026-03-01')]);
$result = $this->repository->getPaginated(['date_from' => '2026-02-01']);
$this->assertCount(1, $result->items());
}
/**
* date_to 필터
*/
public function test_get_paginated_filters_by_date_to(): void
{
MailSendLog::factory()->create(['sent_at' => Carbon::parse('2026-01-15')]);
MailSendLog::factory()->create(['sent_at' => Carbon::parse('2026-03-15')]);
$result = $this->repository->getPaginated(['date_to' => '2026-02-01']);
$this->assertCount(1, $result->items());
}
/**
* 복합 필터 조합
*/
public function test_get_paginated_combines_multiple_filters(): void
{
MailSendLog::factory()->forExtension(ExtensionOwnerType::Core, 'core')->withTemplateType('welcome')->create([
'status' => MailSendStatus::Sent->value,
]);
MailSendLog::factory()->forExtension(ExtensionOwnerType::Core, 'core')->withTemplateType('welcome')->failed()->create();
MailSendLog::factory()->forExtension(ExtensionOwnerType::Module, 'sirsoft-ecommerce')->withTemplateType('welcome')->create();
$result = $this->repository->getPaginated([
'extension_type' => 'core',
'template_type' => 'welcome',
'status' => MailSendStatus::Sent->value,
]);
$this->assertCount(1, $result->items());
}
// ========================================================================
// getStatistics
// ========================================================================
/**
* 빈 테이블에서 통계 반환
*/
public function test_get_statistics_returns_zeros_when_empty(): void
{
$stats = $this->repository->getStatistics();
$this->assertEquals(0, $stats['total']);
$this->assertEquals(0, $stats['sent']);
$this->assertEquals(0, $stats['failed']);
$this->assertEquals(0, $stats['today']);
}
/**
* 올바른 통계 수치 반환
*/
public function test_get_statistics_returns_correct_counts(): void
{
// sent 3건
MailSendLog::factory()->count(3)->create([
'status' => MailSendStatus::Sent->value,
'sent_at' => now(),
]);
// failed 2건
MailSendLog::factory()->failed()->count(2)->create([
'sent_at' => now(),
]);
// 어제 sent 1건
MailSendLog::factory()->create([
'status' => MailSendStatus::Sent->value,
'sent_at' => now()->subDay(),
]);
$stats = $this->repository->getStatistics();
$this->assertEquals(6, $stats['total']);
$this->assertEquals(4, $stats['sent']);
$this->assertEquals(2, $stats['failed']);
$this->assertEquals(5, $stats['today']);
}
}