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>
145 lines
4.4 KiB
Markdown
145 lines
4.4 KiB
Markdown
# Component Guide: Form Requests & Custom Validation Rules
|
|
|
|
Kiểm thử FormRequest và Custom Validation Rules giúp đảm bảo tính toàn vẹn dữ liệu đầu vào và các ràng buộc phân quyền mà không cần tạo request HTTP thật.
|
|
|
|
---
|
|
|
|
## 1. Bản Chất Kiểm Thử
|
|
|
|
- **FormRequest**:
|
|
- Test phương thức `authorize()`: Trả về `true` khi user có quyền, `false` khi không có quyền.
|
|
- Test phương thức `rules()`: Xác nhận các field bắt buộc, format email, min/max length, regex,...
|
|
- **Custom Rule**:
|
|
- Test logic hàm `validate()` (Laravel 10/11 `ValidationRule`) hoặc `passes()` (Laravel 9 `Rule`).
|
|
- Đảm bảo thông báo lỗi khi validation fail là chính xác.
|
|
|
|
---
|
|
|
|
## 2. Mã Mẫu Chuẩn: Custom Validation Rule
|
|
|
|
### Rule Nguồn: `App\Rules\PhoneNumberRule` (Laravel 10/11)
|
|
```php
|
|
namespace App\Rules;
|
|
|
|
use Closure;
|
|
use Illuminate\Contracts\Validation\ValidationRule;
|
|
|
|
class PhoneNumberRule implements ValidationRule
|
|
{
|
|
public function validate(string $attribute, mixed $value, Closure $fail): void
|
|
{
|
|
// Số điện thoại Việt Nam bắt đầu bằng 0 và có 10 chữ số
|
|
if (!is_string($value) || !preg_match('/^0[0-9]{9}$/', $value)) {
|
|
$fail('Trường :attribute phải là số điện thoại Việt Nam hợp lệ gồm 10 chữ số.');
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Test Chuẩn: PHPUnit 10+
|
|
```php
|
|
namespace Tests\Unit\Rules;
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use PHPUnit\Framework\Attributes\DataProvider;
|
|
use App\Rules\PhoneNumberRule;
|
|
|
|
class PhoneNumberRuleTest extends TestCase
|
|
{
|
|
private PhoneNumberRule $rule;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->rule = new PhoneNumberRule();
|
|
}
|
|
|
|
#[Test]
|
|
#[DataProvider('validPhoneNumberProvider')]
|
|
public function it_passes_with_valid_phone_number(string $validPhone): void
|
|
{
|
|
$failed = false;
|
|
$failCallback = function () use (&$failed) {
|
|
$failed = true;
|
|
};
|
|
|
|
$this->rule->validate('phone', $validPhone, $failCallback);
|
|
|
|
$this->assertFalse($failed, "Phone number '{$validPhone}' should be valid.");
|
|
}
|
|
|
|
#[Test]
|
|
#[DataProvider('invalidPhoneNumberProvider')]
|
|
public function it_fails_with_invalid_phone_number(mixed $invalidPhone): void
|
|
{
|
|
$errorMessage = '';
|
|
$failCallback = function (string $message) use (&$errorMessage) {
|
|
$errorMessage = $message;
|
|
};
|
|
|
|
$this->rule->validate('phone', $invalidPhone, $failCallback);
|
|
|
|
$this->assertNotEmpty($errorMessage);
|
|
$this->assertStringContainsString('số điện thoại Việt Nam hợp lệ', $errorMessage);
|
|
}
|
|
|
|
public static function validPhoneNumberProvider(): array
|
|
{
|
|
return [
|
|
'valid mobile 1' => ['0912345678'],
|
|
'valid mobile 2' => ['0868888888'],
|
|
'valid mobile 3' => ['0345678901'],
|
|
];
|
|
}
|
|
|
|
public static function invalidPhoneNumberProvider(): array
|
|
{
|
|
return [
|
|
'starts with 1' => ['1912345678'],
|
|
'too short (9 digits)'=> ['091234567'],
|
|
'too long (11 digits)'=> ['09123456789'],
|
|
'contains letters' => ['09123abcde'],
|
|
'empty string' => [''],
|
|
'non-string (array)' => [['0912345678']],
|
|
];
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Mã Mẫu Chuẩn: FormRequest Validation Rules & Authorize
|
|
|
|
```php
|
|
namespace Tests\Unit\Http\Requests;
|
|
|
|
use Tests\TestCase;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use App\Http\Requests\CreatePostRequest;
|
|
use Illuminate\Support\Facades\Validator;
|
|
|
|
class CreatePostRequestTest extends TestCase
|
|
{
|
|
#[Test]
|
|
public function it_validates_required_fields(): void
|
|
{
|
|
$request = new CreatePostRequest();
|
|
$rules = $request->rules();
|
|
|
|
// 1. Test payload thiếu title
|
|
$validator = Validator::make(['content' => 'Sample content'], $rules);
|
|
$this->assertTrue($validator->fails());
|
|
$this->assertArrayHasKey('title', $validator->errors()->toArray());
|
|
|
|
// 2. Test payload đầy đủ
|
|
$validData = [
|
|
'title' => 'Tiêu đề bài viết hợp lệ',
|
|
'content' => 'Nội dung bài viết đầy đủ chi tiết',
|
|
];
|
|
$validator = Validator::make($validData, $rules);
|
|
$this->assertFalse($validator->fails());
|
|
}
|
|
}
|
|
```
|