2045c856e9
- 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>
189 lines
7.2 KiB
Markdown
189 lines
7.2 KiB
Markdown
# 00. Environment & Setup Guide for Laravel Unit Testing
|
|
|
|
Hướng dẫn thiết lập và chuẩn hóa môi trường kiểm thử (Testing Environment) cho mọi dự án Laravel (Laravel 9, 10, 11).
|
|
|
|
---
|
|
|
|
## 1. Yêu cầu Thư viện & Dependencies (Composer)
|
|
|
|
Trước khi viết bất kỳ file Unit Test nào, dự án cần có đầy đủ các thư viện kiểm thử cần thiết trong `require-dev`.
|
|
|
|
### A. Kiểm tra phiên bản Laravel & Test Framework
|
|
Xác định phiên bản Laravel trong `composer.json`:
|
|
- **Laravel 9 (PHP 8.0 - 8.1)**: Thường đi kèm `phpunit/phpunit: ^9.5`.
|
|
- **Laravel 10 (PHP 8.1 - 8.2)**: Hỗ trợ `phpunit/phpunit: ^10.0` hoặc `pestphp/pest: ^2.0`.
|
|
- **Laravel 11 (PHP 8.2 - 8.3+)**: Mặc định `pestphp/pest: ^2.0|^3.0` hoặc `phpunit/phpunit: ^10.5|^11.0`.
|
|
|
|
### B. Cài đặt các gói cốt lõi (Core Dev Packages)
|
|
|
|
#### Nếu dự án dùng PHPUnit:
|
|
```bash
|
|
composer require --dev phpunit/phpunit mockery/mockery fakerphp/faker --with-all-dependencies
|
|
```
|
|
|
|
#### Nếu dự án dùng Pest PHP:
|
|
```bash
|
|
composer require --dev pestphp/pest pestphp/pest-plugin-laravel mockery/mockery fakerphp/faker --with-all-dependencies
|
|
```
|
|
|
|
#### Các gói bổ trợ tăng tốc & chẩn đoán (Recommended):
|
|
- **Chạy song song (Parallel Testing)**:
|
|
```bash
|
|
composer require --dev brianium/paratest
|
|
# Laravel 9+ có sẵn lệnh: php artisan test --parallel
|
|
```
|
|
- **Làm đẹp output CLI**:
|
|
```bash
|
|
composer require --dev nunomaduro/collision
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Cấu hình Môi trường Test (`phpunit.xml` & `.env.testing`)
|
|
|
|
Một trong những sai lầm nghiêm trọng nhất là để test chạy vào Database dev/staging. Cần cấu hình cách ly tuyệt đối.
|
|
|
|
### A. Tối ưu hóa `phpunit.xml` (hoặc `phpunit.xml.dist`)
|
|
Đảm bảo thẻ `<php>` chứa các cấu hình sau:
|
|
|
|
```xml
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
|
bootstrap="vendor/autoload.php"
|
|
colors="true">
|
|
<testsuites>
|
|
<testsuite name="Unit">
|
|
<directory suffix="Test.php">./tests/Unit</directory>
|
|
</testsuite>
|
|
<testsuite name="Feature">
|
|
<directory suffix="Test.php">./tests/Feature</directory>
|
|
</testsuite>
|
|
</testsuites>
|
|
<php>
|
|
<!-- Môi trường test -->
|
|
<env name="APP_ENV" value="testing"/>
|
|
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
|
|
|
|
<!-- Tăng tốc mã hóa mật khẩu trong lúc test (từ 10-12 vòng xuống 4 vòng) -->
|
|
<env name="BCRYPT_ROUNDS" value="4"/>
|
|
|
|
<!-- Tắt cache, session, queue, mail thật -->
|
|
<env name="CACHE_STORE" value="array"/>
|
|
<env name="CACHE_DRIVER" value="array"/>
|
|
<env name="SESSION_DRIVER" value="array"/>
|
|
<env name="QUEUE_CONNECTION" value="sync"/>
|
|
<env name="MAIL_MAILER" value="array"/>
|
|
<env name="PULSE_ENABLED" value="false"/>
|
|
<env name="TELESCOPE_ENABLED" value="false"/>
|
|
|
|
<!-- Database cách ly: SQLite In-memory -->
|
|
<env name="DB_CONNECTION" value="sqlite"/>
|
|
<env name="DB_DATABASE" value=":memory:"/>
|
|
</php>
|
|
</phpunit>
|
|
```
|
|
|
|
### B. File `.env.testing`
|
|
Nếu dự án ưu tiên dùng `.env.testing` hơn `phpunit.xml`, tạo file `.env.testing` tại thư mục root:
|
|
```ini
|
|
APP_ENV=testing
|
|
APP_KEY=base64:FakeKeyForTestingPurposesOnly1234567890=
|
|
APP_DEBUG=true
|
|
|
|
BCRYPT_ROUNDS=4
|
|
CACHE_STORE=array
|
|
CACHE_DRIVER=array
|
|
SESSION_DRIVER=array
|
|
QUEUE_CONNECTION=sync
|
|
MAIL_MAILER=array
|
|
|
|
DB_CONNECTION=sqlite
|
|
DB_DATABASE=:memory:
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Chiến lược Xử lý Database trong Kiểm thử
|
|
|
|
### Chiến lược 1: SQLite In-memory (Mặc định - Khuyến nghị cho 90% Unit Test)
|
|
- **Ưu điểm**: Tốc độ cực nhanh (vài milliseconds), không tạo rác trên ổ cứng, tự hủy sau mỗi test process.
|
|
- **Yêu cầu**: PHP phải kích hoạt extension `pdo_sqlite` và `sqlite3`.
|
|
|
|
### Chiến lược 2: Xử lý các hàm MySQL đặc thù (MySQL-specific functions)
|
|
Nếu code nguồn dùng các hàm raw của MySQL như `JSON_EXTRACT`, `JSON_CONTAINS`, `DATE_FORMAT`, SQLite sẽ văng lỗi `no such function`.
|
|
**Cách xử lý:**
|
|
1. Đăng ký SQLite custom function trong `TestCase::setUp()`:
|
|
```php
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
if (DB::connection() instanceof \Illuminate\Database\SQLiteConnection) {
|
|
$pdo = DB::connection()->getPdo();
|
|
// Giả lập hàm DATE_FORMAT của MySQL trong SQLite
|
|
$pdo->sqliteCreateFunction('DATE_FORMAT', function ($date, $format) {
|
|
return date('Y-m-d', strtotime($date));
|
|
}, 2);
|
|
|
|
// Giả lập JSON_CONTAINS
|
|
$pdo->sqliteCreateFunction('JSON_CONTAINS', function ($json, $val) {
|
|
$array = json_decode($json, true) ?? [];
|
|
return in_array(trim($val, '"'), $array) ? 1 : 0;
|
|
}, 2);
|
|
}
|
|
}
|
|
```
|
|
2. Nếu dự án có quá nhiều Stored Procedures hoặc SQL phức tạp: Sử dụng một container MySQL test riêng (xem mục Docker bên dưới) thay vì SQLite.
|
|
|
|
---
|
|
|
|
## 4. Chạy Test qua Docker (Docker Integration)
|
|
|
|
### Kịch bản 1: Dự án dùng Laravel Sail
|
|
Laravel Sail đã cấu hình sẵn container test:
|
|
```bash
|
|
# Chạy toàn bộ test
|
|
./vendor/bin/sail test
|
|
|
|
# Chạy riêng Unit Test
|
|
./vendor/bin/sail test --testsuite=Unit
|
|
|
|
# Chạy kèm tính Code Coverage
|
|
./vendor/bin/sail test --coverage
|
|
```
|
|
|
|
### Kịch bản 2: Dự án dùng Custom Docker Compose
|
|
Xác định tên service PHP trong `docker-compose.yml` (thường là `app`, `php`, `backend`, `workspace`):
|
|
```bash
|
|
# Cú pháp chạy
|
|
docker compose exec -T <service_name> php artisan test
|
|
|
|
# Ví dụ với service 'app':
|
|
docker compose exec -T app php artisan test --testsuite=Unit --filter=UserServiceTest
|
|
```
|
|
|
|
### Kịch bản 3: Docker Test Runner độc lập (`templates/docker/docker-compose.test.yml`)
|
|
Nếu dự án chưa có Docker hoặc môi trường Docker chính quá nặng nề, có thể khởi tạo một container test tối giản chỉ chứa PHP-CLI + SQLite + PCOV.
|
|
|
|
---
|
|
|
|
## 5. Cấu hình Code Coverage (PCOV vs Xdebug)
|
|
|
|
Để đo độ phủ test (Coverage):
|
|
- **Khuyến nghị dùng PCOV**: Nhanh gấp 5-10 lần Xdebug, chỉ phục vụ đo coverage không làm chậm quá trình chạy test.
|
|
- Cài đặt trên Ubuntu/Debian container: `pecl install pcov && docker-php-ext-enable pcov`
|
|
- Lệnh chạy: `php artisan test --coverage --min=80`
|
|
- **Nếu dùng Xdebug**: Cần đặt biến môi trường `XDEBUG_MODE=coverage`.
|
|
|
|
---
|
|
|
|
## 6. Checklist Kiểm tra Sẵn sàng (Ready-to-Test Checklist)
|
|
|
|
Trước khi bắt đầu sinh unit test, hãy xác nhận các mục sau:
|
|
1. [ ] Đã chạy `composer install` không lỗi.
|
|
2. [ ] Extension `pdo_sqlite` đã được bật (kiểm tra bằng `php -m | grep sqlite`).
|
|
3. [ ] `APP_KEY` đã tồn tại trong file môi trường test.
|
|
4. [ ] Chạy lệnh `php artisan test` (hoặc tương đương qua Docker) ra kết quả xanh (Pass) với các test mặc định của Laravel.
|
|
5. [ ] Đã cấu hình `DB_DATABASE=:memory:` để bảo vệ dữ liệu dev/local.
|