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>
4.4 KiB
4.4 KiB
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ềtruekhi user có quyền,falsekhi 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,...
- Test phương thức
- Custom Rule:
- Test logic hàm
validate()(Laravel 10/11ValidationRule) hoặcpasses()(Laravel 9Rule). - Đảm bảo thông báo lỗi khi validation fail là chính xác.
- Test logic hàm
2. Mã Mẫu Chuẩn: Custom Validation Rule
Rule Nguồn: App\Rules\PhoneNumberRule (Laravel 10/11)
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+
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
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());
}
}