# 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ẻ `` chứa các cấu hình sau: ```xml ./tests/Unit ./tests/Feature ``` ### 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 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.