feat: enforce >90% SonarQube coverage rules and exclusions for Laravel
- Enhance laravel-unit-test skill with layer-by-layer branch coverage rules - Expand Laravel boilerplate exclusions in sonar-project.properties template - Update SonarQube guide with Laravel comprehensive exclusions
This commit is contained in:
@@ -83,18 +83,40 @@ Người dùng có thể kích hoạt linh hoạt theo các chế độ (từ qu
|
|||||||
- **Dùng Laravel Fakes**: `Http::fake()`, `Queue::fake()`, `Event::fake()`, `Storage::fake()`.
|
- **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.
|
- **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ước 4: Lập Ma Trận Test Scenarios (Đảm Bảo Coverage > 90% Trên SonarQube)
|
||||||
- **Bắt buộc 100% Public Methods**: Mọi phương thức public đều phải có test.
|
Mục tiêu cốt lõi: SonarQube tính cả Line Coverage và Branch Coverage. Để đạt **Coverage > 90%**, Agent phải tuân thủ nghiêm ngặt ma trận sau:
|
||||||
- *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`!
|
1. **100% Public Methods**: Mọi phương thức public của class đều phải có bài test.
|
||||||
- **Bao phủ 100% nhánh rẽ SonarQube**:
|
2. **Quét 100% Nhánh Rẽ (Branch / Condition Coverage)**:
|
||||||
- Mọi toán tử `??` (Null Coalescing) và `?:` (Ternary) phải có test case cho cả 2 vế.
|
- **Toán tử `??` (Null Coalescing)**: Bắt buộc 2 test case (có giá trị & null/fallback).
|
||||||
- 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`.
|
- **Toán tử `?:` (Ternary)**: Bắt buộc 2 test case (true & false).
|
||||||
- Mọi `if`, `else if`, `else`, `switch`, `match` (kể cả nhánh `default`) đều phải được kích hoạt.
|
- **Biểu thức logic `&&` và `||`**: Phải test các kịch bản kết hợp để thỏa mãn điều kiện rẽ nhánh SonarQube.
|
||||||
- **Tối thiểu cho mỗi public method**:
|
- **Khối `try - catch - finally`**: BẮT BUỘC có test case ép mock ném Exception để chạy qua khối `catch`.
|
||||||
- **1 Happy Path**: Đầu vào hợp lệ -> Thực thi thành công -> Trả về đúng kết quả.
|
- **Mọi `if`, `else if`, `else`, `switch`, `match`** (kể cả nhánh `default`).
|
||||||
- **N Edge Cases**: Input biên (0, số âm, rỗng `""`, `[]`, `null`, unicode).
|
3. **Chiến Lược Riêng Cho Từng Tầng Laravel Để Đạt > 90%**:
|
||||||
- **N Exception Cases**: Tham số sai ném `InvalidArgumentException`, service ngoài lỗi ném `PaymentFailedException`,...
|
- **FormRequest (`app/Http/Requests/`)**:
|
||||||
|
- Test `authorize()` trả về cả `true` (cho phép) và `false` (từ chối).
|
||||||
|
- Test `rules()`: Bắt buộc test dữ liệu hợp lệ VÀ test vi phạm cho **từng rule** (`required`, `email`, `max`, `numeric`, `unique`) để phủ 100% các nhánh validator.
|
||||||
|
- **Custom Rules (`app/Rules/`)**: Test cả 2 trường hợp `passes() === true` và `passes() === false` (kèm thông báo `message()`).
|
||||||
|
- **Controllers (`app/Http/Controllers/`)**:
|
||||||
|
- Endpoint Success: 200 OK hoặc 201 Created.
|
||||||
|
- Validation Error: 422 Unprocessable Entity khi payload thiếu/sai.
|
||||||
|
- Unauthorized: 401 Unauthenticated hoặc 403 Forbidden.
|
||||||
|
- Not Found: 404 khi Model ID không tồn tại.
|
||||||
|
- **Services & Actions (`app/Services/`, `app/Actions/`)**:
|
||||||
|
- Happy Path: Đầu vào chuẩn -> kết quả đúng.
|
||||||
|
- Exception Path: Bắt buộc test mock ném ngoại lệ (`PaymentFailedException`,...).
|
||||||
|
- Nếu có `DB::transaction()`: Test cả commit thành công và rollback khi gặp lỗi.
|
||||||
|
- **Jobs (`app/Jobs/`)**:
|
||||||
|
- BẮT BUỘC test phương thức **`handle()`** (với đầy đủ mock S3, Queue, DB, Mail).
|
||||||
|
- BẮT BUỘC test phương thức **`failed(Throwable $e)`**. Tuyệt đối cấm chỉ test helper phụ.
|
||||||
|
- **Policies (`app/Policies/`)**:
|
||||||
|
- Mọi action (`view`, `create`, `update`, `delete`,...) bắt buộc test cả 2 kịch bản: `true` (User có quyền) và `false` (User không có quyền).
|
||||||
|
- **Artisan Commands (`app/Console/Commands/`)**:
|
||||||
|
- Test exit code 0 (`assertExitCode(0)`) khi arguments hợp lệ.
|
||||||
|
- Test exit code 1 khi thiếu arguments hoặc command gặp Exception.
|
||||||
|
- **Repositories (`app/Repositories/`)**:
|
||||||
|
- Test kết quả truy vấn / cập nhật dữ liệu thật trên SQLite in-memory (cấm chỉ assert `Builder::class`).
|
||||||
|
|
||||||
### Bước 5: Sinh Mã Nguồn Test
|
### Bước 5: Sinh Mã Nguồn Test
|
||||||
1. Xác định đường dẫn file test theo quy tắc Mirror:
|
1. Xác định đường dẫn file test theo quy tắc Mirror:
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ sonar.php.tests.reportPath=phpunit-report.xml
|
|||||||
# Inclusions:
|
# Inclusions:
|
||||||
sonar.coverage.inclusions=app/Services/**,app/Actions/**,app/Http/Controllers/**,app/Http/Requests/**,app/Rules/**,app/Jobs/**,app/Policies/**,app/Models/**,app/Repositories/**,app/Console/Commands/**,app/Listeners/**,app/Notifications/**,app/Mail/**
|
sonar.coverage.inclusions=app/Services/**,app/Actions/**,app/Http/Controllers/**,app/Http/Requests/**,app/Rules/**,app/Jobs/**,app/Policies/**,app/Models/**,app/Repositories/**,app/Console/Commands/**,app/Listeners/**,app/Notifications/**,app/Mail/**
|
||||||
|
|
||||||
# Exclusions:
|
# Exclusions: Loại trừ toàn bộ boilerplate, configs, migrations để đảm bảo Coverage > 90%
|
||||||
sonar.coverage.exclusions=app/Providers/**,app/Console/Kernel.php,app/Http/Middleware/TrustProxies.php,bootstrap/**,config/**,database/**,tests/**
|
sonar.coverage.exclusions=app/Providers/**,app/Console/Kernel.php,app/Exceptions/Handler.php,app/Http/Kernel.php,app/Http/Middleware/TrustHosts.php,app/Http/Middleware/TrustProxies.php,app/Http/Middleware/VerifyCsrfToken.php,app/Http/Middleware/EncryptCookies.php,app/Http/Middleware/TrimStrings.php,app/Http/Middleware/PreventRequestsDuringMaintenance.php,bootstrap/**,config/**,database/**,tests/**
|
||||||
sonar.cpd.exclusions=tests/**
|
sonar.cpd.exclusions=tests/**
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -18,5 +18,5 @@ sonar.php.tests.reportPath=phpunit-report.xml
|
|||||||
sonar.coverage.inclusions=app/Services/**,app/Actions/**,app/Http/Controllers/**,app/Http/Requests/**,app/Rules/**,app/Jobs/**,app/Policies/**,app/Models/**,app/Repositories/**,app/Console/Commands/**,app/Listeners/**,app/Notifications/**,app/Mail/**
|
sonar.coverage.inclusions=app/Services/**,app/Actions/**,app/Http/Controllers/**,app/Http/Requests/**,app/Rules/**,app/Jobs/**,app/Policies/**,app/Models/**,app/Repositories/**,app/Console/Commands/**,app/Listeners/**,app/Notifications/**,app/Mail/**
|
||||||
|
|
||||||
# Exclusions: Loại trừ boilerplate, migrations, seeders, config để đảm bảo Coverage > 90%
|
# Exclusions: Loại trừ boilerplate, migrations, seeders, config để đảm bảo Coverage > 90%
|
||||||
sonar.coverage.exclusions=app/Providers/**,app/Console/Kernel.php,app/Http/Middleware/TrustProxies.php,bootstrap/**,config/**,database/**,tests/**
|
sonar.coverage.exclusions=app/Providers/**,app/Console/Kernel.php,app/Exceptions/Handler.php,app/Http/Kernel.php,app/Http/Middleware/TrustHosts.php,app/Http/Middleware/TrustProxies.php,app/Http/Middleware/VerifyCsrfToken.php,app/Http/Middleware/EncryptCookies.php,app/Http/Middleware/TrimStrings.php,app/Http/Middleware/PreventRequestsDuringMaintenance.php,bootstrap/**,config/**,database/**,tests/**
|
||||||
sonar.cpd.exclusions=tests/**
|
sonar.cpd.exclusions=tests/**
|
||||||
|
|||||||
Reference in New Issue
Block a user