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>
194 lines
5.8 KiB
Markdown
194 lines
5.8 KiB
Markdown
# 06. Hướng Dẫn Nâng Cao: PHP 8.4+ & Laravel 12 / 13 (Latest & Future-Proof)
|
|
|
|
Tài liệu này chuẩn bị đầy đủ các kỹ thuật kiểm thử cho các phiên bản PHP và Laravel mới nhất, bao gồm **PHP 8.4**, **Laravel 12 & 13**, **PHPUnit 11/12** và **Pest PHP v3**.
|
|
|
|
---
|
|
|
|
## 1. Kiểm Thử Các Tính Năng Mới Của PHP 8.4
|
|
|
|
PHP 8.4 giới thiệu nhiều thay đổi mang tính cách mạng trong cú pháp lập trình hướng đối tượng. Unit Test cần thích ứng chính xác:
|
|
|
|
### A. Property Hooks (`get` / `set`)
|
|
Thay vì viết getter/setter truyền thống hoặc Eloquent Accessor cũ, PHP 8.4 cho phép định nghĩa hooks ngay trên thuộc tính:
|
|
|
|
```php
|
|
// DTO hoặc Model trong PHP 8.4
|
|
class UserProfile
|
|
{
|
|
public string $firstName;
|
|
public string $lastName;
|
|
|
|
// Property Hook tự động tính toán
|
|
public string $fullName {
|
|
get => trim("{$this->firstName} {$this->lastName}");
|
|
}
|
|
|
|
// Property Hook kiểm soát gán giá trị
|
|
public string $email {
|
|
set {
|
|
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
|
throw new \InvalidArgumentException('Email không hợp lệ');
|
|
}
|
|
$this->email = strtolower($value);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Cách viết Unit Test:
|
|
```php
|
|
#[Test]
|
|
public function it_calculates_full_name_via_property_hook(): void
|
|
{
|
|
$profile = new UserProfile();
|
|
$profile->firstName = 'Thien';
|
|
$profile->lastName = 'Phan';
|
|
|
|
// Kiểm thử get hook
|
|
$this->assertSame('Thien Phan', $profile->fullName);
|
|
}
|
|
|
|
#[Test]
|
|
public function it_throws_exception_when_setting_invalid_email_hook(): void
|
|
{
|
|
$profile = new UserProfile();
|
|
|
|
$this->expectException(\InvalidArgumentException::class);
|
|
// Kiểm thử set hook
|
|
$profile->email = 'invalid-email-format';
|
|
}
|
|
```
|
|
|
|
### B. Asymmetric Visibility (`public private(set)`)
|
|
PHP 8.4 cho phép thuộc tính có quyền đọc công khai nhưng chỉ được sửa từ bên trong class:
|
|
|
|
```php
|
|
class BankAccount
|
|
{
|
|
// Đọc public từ ngoài, nhưng chỉ private method được set
|
|
public private(set) int $balance = 0;
|
|
|
|
public function deposit(int $amount): void
|
|
{
|
|
if ($amount <= 0) {
|
|
throw new \InvalidArgumentException('Số tiền nạp phải > 0');
|
|
}
|
|
$this->balance += $amount;
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Cách viết Unit Test:
|
|
```php
|
|
#[Test]
|
|
public function it_updates_balance_via_public_api_and_allows_public_reading(): void
|
|
{
|
|
$account = new BankAccount();
|
|
|
|
// Đọc trạng thái ban đầu
|
|
$this->assertSame(0, $account->balance);
|
|
|
|
// Kích hoạt method hợp lệ
|
|
$account->deposit(500_000);
|
|
$this->assertSame(500_000, $account->balance);
|
|
|
|
// Cố tình ghi đè từ ngoài sẽ gây Error (PHP Fatal Error)
|
|
// Unit test tập trung xác nhận method nội bộ thay đổi đúng giá trị
|
|
}
|
|
```
|
|
|
|
### C. Hàm Array Mới (`array_find`, `array_any`, `array_all`)
|
|
Kiểm thử các business logic sử dụng các hàm tiện ích mảng mới của PHP 8.4.
|
|
|
|
---
|
|
|
|
## 2. Kiểm Thử Kiến Trúc Laravel Hiện Đại (Laravel 11, 12, 13)
|
|
|
|
### A. Concurrency API (`Concurrency::fake()`)
|
|
Từ Laravel 11 và tiếp tục hoàn thiện trên Laravel 12/13, Laravel cung cấp Facade `Concurrency` để chạy các tác vụ song song:
|
|
|
|
```php
|
|
// Trong Service
|
|
public function fetchDashboardData(): array
|
|
{
|
|
return Concurrency::run([
|
|
fn () => $this->userService->getStats(),
|
|
fn () => $this->orderService->getRevenue(),
|
|
]);
|
|
}
|
|
```
|
|
|
|
#### Cách viết Unit Test:
|
|
```php
|
|
use Illuminate\Support\Facades\Concurrency;
|
|
|
|
#[Test]
|
|
public function it_executes_concurrent_tasks_correctly(): void
|
|
{
|
|
// Giả lập Concurrency để chạy tuần tự trong lúc test
|
|
Concurrency::fake();
|
|
|
|
$dashboardData = $dashboardService->fetchDashboardData();
|
|
|
|
$this->assertCount(2, $dashboardData);
|
|
}
|
|
```
|
|
|
|
### B. Context API (`Context::fake()`)
|
|
Laravel Context cho phép theo dõi metadata xuyên suốt vòng đời request và background jobs:
|
|
|
|
```php
|
|
use Illuminate\Support\Facades\Context;
|
|
|
|
#[Test]
|
|
public function it_attaches_trace_id_to_context(): void
|
|
{
|
|
$middleware = new TraceContextMiddleware();
|
|
$request = Request::create('/api/orders', 'GET');
|
|
$request->headers->set('X-Trace-ID', 'trace-xyz-123');
|
|
|
|
$middleware->handle($request, fn () => response('OK'));
|
|
|
|
$this->assertSame('trace-xyz-123', Context::get('trace_id'));
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Pest PHP v3: Architecture Testing (`arch()`)
|
|
|
|
Trong các dự án Laravel 11/12/13 hiện đại dùng Pest v3, ngoài việc test từng method, chúng ta có thể viết **Architectural Tests** để kiểm soát toàn bộ cấu trúc code:
|
|
|
|
```php
|
|
// tests/Unit/ArchitectureTest.php
|
|
|
|
describe('Architecture Rules', function () {
|
|
test('Controllers do not directly use Models (must use Services/Actions)')
|
|
->expect('App\Http\Controllers')
|
|
->not->toUse('App\Models')
|
|
->ignoring('App\Http\Controllers\Auth');
|
|
|
|
test('Services must be readonly or final')
|
|
->expect('App\Services')
|
|
->toBeFinal();
|
|
|
|
test('All Value Objects must be immutable')
|
|
->expect('App\ValueObjects')
|
|
->toBeReadonly();
|
|
|
|
test('No debugging functions left in code')
|
|
->expect(['dd', 'dump', 'ray', 'var_dump'])
|
|
->not->toBeUsed();
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Tương Thích PHPUnit 11 & 12
|
|
|
|
1. **Loại bỏ hoàn toàn DocBlock**: PHPUnit 11+ deprecate và loại bỏ chú thích dạng `@test`, `@dataProvider`. Bắt buộc 100% sử dụng:
|
|
- `#[PHPUnit\Framework\Attributes\Test]`
|
|
- `#[PHPUnit\Framework\Attributes\DataProvider('providerMethod')]`
|
|
- `#[PHPUnit\Framework\Attributes\TestDox('Mô tả tiếng Việt dễ đọc')]`
|
|
2. **Event-driven Internal System**: PHPUnit 11 quản lý vòng đời test hoàn toàn bằng sự kiện, giúp execution nhanh hơn và đo lường chính xác hơn.
|