# 🍰 CakePHP Unit & Integration Testing Guide > **Cẩm nang toàn diện về quy chuẩn, kiến trúc và phương pháp kiểm thử tự động cho dự án PHP CakePHP (3.x, 4.x, 5.x+, PHP 7.4 đến 8.4+).** --- ## 1. Triết Lý & Nguyên Tắc Cốt Lõi 1. **Mô hình AAA (Arrange - Act - Assert)**: - Mọi phương thức test bắt buộc phải có phân tách rõ ràng 3 bước: - `// Arrange`: Chuẩn bị payload, cấu hình session/auth, mock dependency. - `// Act`: Thực thi phương thức (hoặc gọi HTTP endpoint, hoặc gọi console command). - `// Assert`: So sánh kết quả, kiểm tra HTTP code, kiểm tra dữ liệu thay đổi trong DB. 2. **Bảo Vệ Database Tuyệt Đối (Zero Leakage)**: - Mọi test tương tác cơ sở dữ liệu **PHẢI sử dụng kết nối `test`** (tốt nhất là SQLite in-memory `:memory:`). - **Tuyệt đối không chạy test trên kết nối `default`** (tránh xóa nhầm hoặc làm bẩn dữ liệu dev/local). - Sử dụng cơ chế Transaction Strategy hoặc Fixture Strategy của CakePHP để rollback dữ liệu tự động sau mỗi test. 3. **Phân Biệt Rõ Mocking vs Fixtures**: - **Dùng Fixtures**: Khi kiểm thử Table, Custom Finder, ORM query phức tạp. - **Dùng Mocks**: Khi gọi Web service bên ngoài (Stripe, Twilio, AWS S3, External API) hoặc các Service Interface trừu tượng. - **Không Mock**: Entity (dùng Entity thật), Array, DTOs, Value Objects. --- ## 2. Các Trait Kiểm Thử Quan Trọng của CakePHP CakePHP cung cấp sẵn các Trait vô cùng mạnh mẽ trong `Cake\TestSuite`: ### 1. `Cake\TestSuite\IntegrationTestTrait` (Dành cho Controllers / HTTP Endpoints) Cho phép gửi request HTTP ảo vào ứng dụng CakePHP mà không cần mở web server thật: ```php use Cake\TestSuite\IntegrationTestTrait; use Cake\TestSuite\TestCase; class ArticlesControllerTest extends TestCase { use IntegrationTestTrait; public function testIndex(): void { $this->get('/articles'); $this->assertResponseOk(); $this->assertResponseContains('Latest Articles'); } public function testAddPostWithAuthAndCsrf(): void { // Giả lập đăng nhập $this->session(['Auth.User.id' => 1, 'Auth.User.role' => 'admin']); // Bật CSRF & Security token $this->enableCsrfToken(); $this->enableSecurityToken(); $this->post('/articles/add', [ 'title' => 'CakePHP Testing Pro', 'body' => 'High quality tests.', ]); $this->assertResponseSuccess(); $this->assertRedirect(['action' => 'index']); } } ``` ### 2. `Cake\Console\TestSuite\ConsoleIntegrationTestTrait` (Dành cho Commands / Shells) Giúp test CLI Command một cách trực quan: ```php use Cake\Console\TestSuite\ConsoleIntegrationTestTrait; use Cake\TestSuite\TestCase; class SendReportCommandTest extends TestCase { use ConsoleIntegrationTestTrait; public function setUp(): void { parent::setUp(); $this->useCommandRunner(); } public function testExecuteSuccess(): void { $this->exec('send_report --daily'); $this->assertExitSuccess(); $this->assertOutputContains('Reports sent successfully'); } } ``` ### 3. `Cake\TestSuite\EmailTrait` (Dành cho Mailers) Kiểm tra email được gửi đi mà không thực sự gửi qua SMTP: ```php use Cake\TestSuite\EmailTrait; use Cake\TestSuite\TestCase; class UserMailerTest extends TestCase { use EmailTrait; public function testWelcomeEmail(): void { $mailer = new UserMailer(); $mailer->send('welcome', ['user@example.com', 'Alex']); $this->assertMailSentTo('user@example.com'); $this->assertMailContainsText('Welcome Alex'); } } ``` --- ## 3. Quản Lý Test Database & Fixtures ### Cấu hình SQLite In-Memory trong `config/app_local.php`: ```php 'Datasources' => [ 'test' => [ 'className' => 'Cake\Database\Connection', 'driver' => 'Cake\Database\Driver\Sqlite', 'database' => ':memory:', 'encoding' => 'utf8', 'timezone' => 'UTC', 'cacheMetadata' => true, ], ], ``` ### Khai báo Fixtures trong Test Case: ```php protected array $fixtures = [ 'app.Users', 'app.Articles', ]; ``` --- ## 4. Cách Chạy Test Tối Ưu 1. **Chạy qua Smart Test Runner**: ```bash ./test-runner.sh # Chạy 1 file test cụ thể: ./test-runner.sh --filter=ArticlesControllerTest ``` 2. **Chạy qua CakePHP CLI**: ```bash bin/cake test app tests/TestCase/Model/Table/ArticlesTableTest.php ``` 3. **Chạy qua PHPUnit trực tiếp**: ```bash vendor/bin/phpunit --filter=ArticlesTableTest ``` 4. **Đo Code Coverage**: ```bash ./test-runner.sh --coverage ```