docs: standardize pro 3-step testing workflow and add SonarQube guide
- Update README.md with recommended 3-step decoupled workflow (audit -> batch write -> terminal run) - Add docs/10-sonarqube-100-percent-coverage-guide.md covering line/branch coverage and Clover XML export - Update /laravel-unit-test skill definition prioritizing decoupled batch generation - Fix remote installer URLs to official Smartgift Git server Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# 10. Chiến Lược Đạt 100% Code Coverage Trên SonarQube
|
||||
|
||||
Tài liệu này giải thích chi tiết cách cấu hình và kỹ thuật viết Unit Test để đạt điểm tối đa (Line & Branch Coverage) khi quét qua hệ thống phân tích chất lượng mã nguồn **SonarQube / SonarCloud**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Công Thức Tính Độ Phủ Của SonarQube
|
||||
|
||||
SonarQube tính toán chỉ số Coverage tổng hợp dựa trên cả dòng lệnh (Lines) lẫn điều kiện rẽ nhánh (Branches / Conditions):
|
||||
|
||||
$$\text{Coverage} = \frac{\text{Lines Covered} + \text{Branches Covered}}{\text{Total Lines} + \text{Total Branches}} \times 100\%$$
|
||||
|
||||
> ⚠️ **Lưu ý quan trọng**: Nếu một dòng code chạy qua nhưng chỉ thỏa mãn 1 trong 2 nhánh của toán tử ternary (`?:`) hoặc null coalescing (`??`), SonarQube sẽ tính là **Partially Covered** và trừ điểm độ phủ của dòng đó.
|
||||
|
||||
---
|
||||
|
||||
## 2. Cấu Hình Cốt Lõi: Scope & Exclusions
|
||||
|
||||
Không bao giờ đưa các file cấu hình hoặc framework boilerplate vào phạm vi đo Coverage. Trong file cấu hình `sonar-project.properties` tại thư mục gốc dự án:
|
||||
|
||||
```properties
|
||||
# 1. Khai báo đường dẫn file báo cáo Coverage sinh ra từ PHPUnit
|
||||
sonar.php.coverage.reportPaths=coverage.xml
|
||||
|
||||
# 2. Phạm vi đo Coverage: CHỈ ĐO CÁC TẦNG CHỨA LOGIC NGHIỆP VỤ
|
||||
sonar.coverage.inclusions=app/Services/**,app/Actions/**,app/Rules/**,app/Jobs/**,app/Policies/**,app/Http/Requests/**,app/Models/**
|
||||
|
||||
# 3. Loại trừ các file framework, boilerplate không cần viết Unit Test
|
||||
sonar.coverage.exclusions=app/Providers/**,app/Console/Kernel.php,app/Http/Middleware/TrustProxies.php,bootstrap/**,config/**,database/**,tests/**
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Cách Xuất Báo Cáo Coverage Chuẩn SonarQube (`coverage.xml`)
|
||||
|
||||
Trong file `phpunit.xml` (hoặc `phpunit.xml.dist`), bổ sung cấu hình xuất định dạng Clover XML:
|
||||
|
||||
```xml
|
||||
<coverage>
|
||||
<report>
|
||||
<clover outputFile="coverage.xml"/>
|
||||
<html outputDirectory="coverage-html"/>
|
||||
</report>
|
||||
</coverage>
|
||||
```
|
||||
|
||||
Hoặc khi chạy lệnh thông qua `test-runner.sh`:
|
||||
```bash
|
||||
./test-runner.sh --coverage-clover coverage.xml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Checklist Đánh Bay Các Lỗi "Uncovered Branches" Của SonarQube
|
||||
|
||||
Khi AI hoặc dev viết test, cần kiểm tra 5 bẫy rẽ nhánh sau để chạm mốc 100%:
|
||||
|
||||
### A. Toán tử Null Coalescing (`??`)
|
||||
```php
|
||||
// Code nguồn:
|
||||
$timeout = $config['timeout'] ?? 30;
|
||||
```
|
||||
- **Test Case 1 (Left branch)**: Truyền `$config` có chứa key `'timeout' => 60`.
|
||||
- **Test Case 2 (Right branch)**: Truyền `$config = []` (không có key `'timeout'`).
|
||||
|
||||
### B. Toán tử Ternary (`?:`) và Guard Clauses
|
||||
```php
|
||||
// Code nguồn:
|
||||
return $user->isVip() ? 0.2 : 0.05;
|
||||
```
|
||||
- **Test Case 1**: Truyền user với `isVip() === true`.
|
||||
- **Test Case 2**: Truyền user với `isVip() === false`.
|
||||
|
||||
### C. Khối `try - catch - finally`
|
||||
```php
|
||||
// Code nguồn:
|
||||
try {
|
||||
return $this->gateway->charge($amount);
|
||||
} catch (PaymentException $e) {
|
||||
Log::error($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
```
|
||||
- **Bắt buộc**: Phải có 1 bài test giả lập mock `->andThrow(new PaymentException('Lỗi cổng thanh toán'))` để ép luồng chạy vào trong khối `catch`.
|
||||
|
||||
### D. Switch / Match Expression
|
||||
Mọi case trong `match` hoặc `switch` (kể cả nhánh `default`) đều phải có ít nhất 1 bài test kích hoạt.
|
||||
Reference in New Issue
Block a user