--- name: laravel-unit-test description: Phân tích một class mã nguồn PHP Laravel bất kỳ và tự động sinh file Unit Test hoàn chỉnh đạt chuẩn AAA, cô lập cao và bao phủ biên. --- # Skill: Laravel Unit Test Generator Skill này là công cụ chính để tự động tạo ra file Unit Test cho bất kỳ class nào trong dự án Laravel (Service, Action, Controller, Job, FormRequest, Policy, Rule,...). ## Cách kích hoạt Người dùng có thể kích hoạt linh hoạt theo các chế độ (từ quy trình chuẩn Pro 3 bước cho dự án lớn đến file đơn lẻ): ### 🏆 QUY TRÌNH CHUẨN PRO CHO DỰ ÁN LỚN (KHUYÊN DÙNG NHẤT): Để tránh bị tràn context token và đảm bảo viết sâu 100% từng nhánh SonarQube, hãy tách biệt 2 pha: **PHA VIẾT (Generation)** và **PHA CHẠY (Execution)**: 1. **Bước 1: Quét bản đồ dự án (`--untested`)**: ```text /laravel-unit-test --untested ``` *Liệt kê danh sách class chưa có test theo độ ưu tiên: Services/Actions -> Requests/Rules -> Jobs/Policies.* 2. **Bước 2: Viết test tập trung theo từng tầng (CHỈ VIẾT, CHƯA CHẠY TEST)**: ```text /laravel-unit-test app/Services/ # Sau khi xong, viết tiếp: /laravel-unit-test app/Actions/ /laravel-unit-test app/Http/Requests/ ``` *AI dồn 100% token tập trung sinh test sâu, đầy đủ Happy Path, Edge Cases, Exception và Branch Coverage.* 3. **Bước 3: Chạy test đồng loạt ngoài Terminal & Nghiệm thu**: ```bash ./test-runner.sh --coverage ``` *Chạy 1 lần duy nhất trên In-memory SQLite siêu tốc, đo độ phủ và xuất file báo cáo.* --- ### ⚡ CÁC CHẾ ĐỘ TIỆN ÍCH KHÁC: 4. **Chế độ Autopilot Khép Kín: Viết & Chạy Test Ngay (`--all --run` hoặc `--autopilot`)**: ```text /laravel-unit-test --all --run ``` *Dành cho dự án vừa và nhỏ: AI tự lập manifest, viết đến đâu chạy `./test-runner.sh` ngay đến đó, tự động sửa lỗi (Auto-Healing) nếu test fail.* 5. **Chế độ Viết Cho 1 File & Test Luôn (`--run`)**: ```text /laravel-unit-test app/Services/PaymentService.php --run ``` 6. **Chế độ Theo Git Diff (Dành Cho Pull Request)**: ```text /laravel-unit-test --changed ``` 7. **Chế độ File đơn lẻ**: ```text /laravel-unit-test app/Services/PaymentService.php ``` --- ## Quy trình 6 Bước Tự Động của Agent ### Bước 1: Khảo sát Môi trường & Framework 1. Đọc `composer.json` để xác định Framework test của dự án: - Nếu có `pestphp/pest`: Tạo test theo định dạng **Pest PHP**. - Nếu có `phpunit/phpunit`: - PHP >= 8.1 & PHPUnit 10+: Dùng **PHP 8 Attributes (`#[Test]`, `#[DataProvider]`)**. - PHP < 8.1 hoặc PHPUnit 9: Dùng **DocBlock (`/** @test */`)**. ### Bước 2: Phân tích File Nguồn 1. Đọc toàn bộ nội dung file class nguồn được chỉ định. 2. Xác định: - **Loại Component**: Service, Action, Controller, FormRequest, Model, Job, Policy, Middleware,... - **Constructor Dependencies**: Các class/interface được inject vào qua `__construct()`. - **Public Methods**: Danh sách các hàm cần test. - **Kiểu dữ liệu & Logic phân nhánh**: Các lệnh `if/else`, `try/catch`, `throw`, type hints của params và return types. ### Bước 3: Phân Loại Mock vs Real Object - **Mock bằng Mockery**: Các Interface, Repository, 3rd Party Client, Mailer, Logger. - **Dùng Laravel Fakes**: `Http::fake()`, `Queue::fake()`, `Event::fake()`, `Storage::fake()`. - **Dùng Object thật (Không Mock)**: DTOs, Value Objects, Collections, Request payload dạng mảng. ### Bước 4: Lập Ma Trận Test Scenarios (Bắt Buộc Đầy Đủ & Không Bỏ Sót) - **Bắt buộc 100% Public Methods**: Mọi phương thức public đều phải có test. - *Nếu là Job / Command*: **BẮT BUỘC 100% phải test phương thức `handle()`** và `failed()`. Tuyệt đối CẤM chỉ test hàm helper phụ (`buildRedisKey`) bằng reflection! - *Nếu là Repository*: **BẮT BUỘC phải test kết quả truy vấn / cập nhật dữ liệu thật** trên SQLite in-memory, tuyệt đối CẤM chỉ assert `Builder::class`! - **Bao phủ 100% nhánh rẽ SonarQube**: - Mọi toán tử `??` (Null Coalescing) và `?:` (Ternary) phải có test case cho cả 2 vế. - Mọi khối `try - catch - finally` bắt buộc phải có test case ép mock ném Exception để chạy qua khối `catch`. - Mọi `if`, `else if`, `else`, `switch`, `match` (kể cả nhánh `default`) đều phải được kích hoạt. - **Tối thiểu cho mỗi public method**: - **1 Happy Path**: Đầu vào hợp lệ -> Thực thi thành công -> Trả về đúng kết quả. - **N Edge Cases**: Input biên (0, số âm, rỗng `""`, `[]`, `null`, unicode). - **N Exception Cases**: Tham số sai ném `InvalidArgumentException`, service ngoài lỗi ném `PaymentFailedException`,... ### Bước 5: Sinh Mã Nguồn Test 1. Xác định đường dẫn file test theo quy tắc Mirror: - Nguồn: `app/Services/OrderService.php` - Đích: `tests/Unit/Services/OrderServiceTest.php` 2. Tham chiếu hướng dẫn tương ứng trong `docs/components/` và template trong `templates/`. 3. Viết đầy đủ code: - Tuân thủ mô hình **AAA** (`// Arrange`, `// Act`, `// Assert`). - Mock expectation có số lần gọi nghiêm ngặt: `->once()`, `->never()`. - Dùng Strict assertion: `$this->assertSame()` hoặc `expect(...)->toBe()`. - Đảm bảo quét sạch tất cả các nhánh điều kiện để SonarQube Line & Branch Coverage đạt > 85% - 95%. ### Bước 6: Thẩm định & Lưu File 1. Tự kiểm tra file test qua `rules/verification-checklist.md`. 2. Ghi file test vào thư mục `tests/Unit/...`. 3. In ra lệnh chạy test gợi ý: ```bash php artisan test --filter=OrderServiceTest # Hoặc qua docker runner: ./templates/docker/test-runner.sh --filter=OrderServiceTest ```