Files
agent-unit-testing/docs/components/11-artisan-commands.md
T
Pham-Tan-Thien 2045c856e9 feat: complete Smartgift AI Laravel unit testing toolkit
- Add 10 core testing guides (setup, AAA principles, PHPUnit/Pest, mocking, anti-patterns, PHP 8.4+, debugging, data factories, advanced edge cases)
- Add 13 component testing guides covering all Laravel layers
- Add standard templates for PHPUnit 10/11 and Pest v2/v3 including ArchitectureTest
- Add Docker smart test runner, dependency installer, and CI/CD templates (GitHub Actions, GitLab CI)
- Add 4 Claude Code skills (laravel-test-setup, laravel-unit-test with --all mode, laravel-test-review, laravel-mock-helper)
- Add single unified installer script (sg-install-unit-testing.sh) with global support, CLI runners, and 1-click updater (sg-test-update)
- Add comprehensive documentation (README.md, USAGE-GUIDE.md)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-07 16:41:37 +07:00

3.3 KiB

Component Guide: Artisan Console Commands

Artisan Commands xử lý các công việc chạy từ dòng lệnh (CLI), cron jobs, và lệnh bảo trì hệ thống.


1. Bản Chất Kiểm Thử Console Command

Khi test một Artisan Command, cần kiểm tra:

  1. Exit Code: Trả về Command::SUCCESS (0) khi hoàn thành, hoặc Command::FAILURE (1) / Command::INVALID (2) khi có lỗi.
  2. Output trên màn hình: Kiểm tra dòng thông báo in ra bằng expectsOutput(), doesntExpectOutput(), expectsTable().
  3. User Interaction: Kiểm tra câu hỏi tương tác như expectsConfirmation(), expectsQuestion(), expectsChoice().
  4. Service Execution: Đảm bảo Command gọi đúng Service xử lý logic ngầm bên dưới.

2. Mã Mẫu Chuẩn: Console Command Test

Command Nguồn: App\Console\Commands\PruneOldLogsCommand

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Services\LogCleanupService;

class PruneOldLogsCommand extends Command
{
    protected $signature = 'logs:prune {--days=30 : Số ngày lưu log cũ} {--force : Thực thi mà không hỏi lại}';
    protected $description = 'Xóa các file log cũ hơn số ngày quy định';

    public function handle(LogCleanupService $cleanupService): int
    {
        $days = (int) $this->option('days');

        if ($days <= 0) {
            $this->error('Số ngày phải lớn hơn 0.');
            return self::INVALID;
        }

        if (!$this->option('force') && !$this->confirm("Bạn có chắc chắn muốn xóa log cũ hơn {$days} ngày?")) {
            $this->info('Đã hủy thao tác.');
            return self::SUCCESS;
        }

        $deletedCount = $cleanupService->deleteLogsOlderThan($days);
        $this->info("Đã dọn dẹp thành công {$deletedCount} file log.");

        return self::SUCCESS;
    }
}

Test Chuẩn: PHPUnit 10+

namespace Tests\Unit\Console\Commands;

use Tests\TestCase;
use PHPUnit\Framework\Attributes\Test;
use Mockery;
use App\Services\LogCleanupService;
use Illuminate\Console\Command;

class PruneOldLogsCommandTest extends TestCase
{
    #[Test]
    public function it_fails_when_days_option_is_zero_or_negative(): void
    {
        $this->artisan('logs:prune --days=0')
            ->expectsOutput('Số ngày phải lớn hơn 0.')
            ->assertExitCode(Command::INVALID);
    }

    #[Test]
    public function it_cancels_pruning_when_user_declines_confirmation(): void
    {
        $this->artisan('logs:prune --days=15')
            ->expectsConfirmation('Bạn có chắc chắn muốn xóa log cũ hơn 15 ngày?', 'no')
            ->expectsOutput('Đã hủy thao tác.')
            ->assertExitCode(Command::SUCCESS);
    }

    #[Test]
    public function it_prunes_logs_successfully_when_forced(): void
    {
        // Mock service
        $cleanupServiceMock = Mockery::mock(LogCleanupService::class);
        $cleanupServiceMock->shouldReceive('deleteLogsOlderThan')
            ->once()
            ->with(30)
            ->andReturn(12);

        $this->app->instance(LogCleanupService::class, $cleanupServiceMock);

        $this->artisan('logs:prune --days=30 --force')
            ->expectsOutput('Đã dọn dẹp thành công 12 file log.')
            ->assertExitCode(Command::SUCCESS);
    }
}