Laravel Testing với Pest 5 năm 2026: TIA, Mocking và Câu Hỏi Phỏng Vấn
Nắm vững các phương pháp kiểm thử Laravel với Pest 5, Test Impact Analysis, Mockery, facade fake và architecture test. Bao gồm unit test, feature test, chiến lược mocking và câu hỏi phỏng vấn phổ biến cho developer Laravel.

Các phương pháp kiểm thử Laravel đã thay đổi đáng kể với Pest 5, công cụ TIA (Test Impact Analysis), và PHPUnit 13. Laravel 13 được tích hợp sẵn hỗ trợ Pest, mang lại trải nghiệm kiểm thử biểu cảm và ngắn gọn hơn so với PHPUnit thuần túy. Hướng dẫn này đề cập đến các pattern quan trọng cho cả ứng dụng production và phỏng vấn kỹ thuật.
Pest 5 (xây dựng trên PHPUnit 13) là framework kiểm thử mặc định cho Laravel 13. Framework này yêu cầu PHP 8.4+ và giới thiệu công cụ TIA, xác minh AI agent tích hợp, tích hợp PHPStan, và time-balanced sharding mặc định.
Cấu Hình Pest 5 Trong Dự Án Laravel 13
Mọi ứng dụng Laravel 13 mới đều tự động scaffold Pest. Với các dự án hiện có, việc di chuyển từ Pest 4 chỉ mất vài phút vì điều cần xem xét chính là khả năng tương thích PHPUnit 13. Cấu hình nằm trong tests/Pest.php, nơi các trait và helper method toàn cục được đăng ký.
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()
->extend(Tests\TestCase::class)
->use(RefreshDatabase::class)
->in('Feature');Một file duy nhất này thay thế trait CreatesApplication cũ và kế thừa base test class. Trait RefreshDatabase bọc mỗi test trong transaction database, tự động rollback các thay đổi.
use App\Models\User;
it('registers a new user with valid data', function () {
$response = $this->postJson('/api/register', [
'name' => 'Jane Doe',
'email' => 'jane@example.com',
'password' => 'SecurePass123!',
'password_confirmation' => 'SecurePass123!',
]);
$response->assertStatus(201)
->assertJsonStructure(['user' => ['id', 'name', 'email']]);
expect(User::where('email', 'jane@example.com')->exists())->toBeTrue();
});API expect() của Pest kết hợp tự nhiên với các assertion của PHPUnit. Lệnh gọi assertJsonStructure xác thực cấu trúc response, trong khi expect()->toBeTrue() xác nhận trạng thái database. Cả hai phong cách cùng tồn tại mà không xung đột.
Test Impact Analysis: Tính Năng Nổi Bật Của Pest 5
Công cụ TIA là yếu tố giúp Pest 5 mang tính chuyển đổi cho các codebase lớn. Trong lần chạy đầu tiên, Pest ghi lại test nào truy cập file nào. Mỗi lần chạy tiếp theo chỉ thực thi các test bị ảnh hưởng bởi thay đổi và phát lại kết quả đã cache cho phần còn lại.
# First run: records baseline (requires PCOV or Xdebug)
php artisan test
# Subsequent runs: only affected tests execute
php artisan testTest suite của Laravel Cloud, chứa hơn 19.000 test, giảm từ khoảng ba phút xuống năm giây khi bật TIA. Công cụ này hiểu không chỉ file PHP: nó phát hiện thay đổi trong migration, template Blade, và các component JavaScript dùng chung.
TIA yêu cầu coverage driver (PCOV hoặc Xdebug) để ghi baseline. Với các pipeline CI, các mapping đã cache được lưu giữa các lần chạy, làm cho hiệu quả tăng dần theo thời gian.
Unit Test và Feature Test Trong Laravel
Sự khác biệt giữa unit test và feature test trong Laravel quyết định phần nào của framework được khởi động. Unit test chạy mà không cần container ứng dụng, giúp chúng nhanh hơn nhưng giới hạn ở logic thuần túy. Feature test khởi động toàn bộ ứng dụng, cho phép gọi HTTP, truy vấn database và resolve service.
use App\Services\PriceCalculator;
describe('PriceCalculator', function () {
it('applies a percentage discount correctly', function () {
$calculator = new PriceCalculator();
// 20% off a 150.00 base price
$result = $calculator->applyDiscount(150.00, 20);
expect($result)->toBe(120.00);
});
it('rejects negative discount values', function () {
$calculator = new PriceCalculator();
expect(fn () => $calculator->applyDiscount(100.00, -5))
->toThrow(InvalidArgumentException::class);
});
});Unit test nhắm vào các class độc lập không có dependency bên ngoài. Khối describe nhóm các assertion liên quan, và Pest 5 hỗ trợ khối describe lồng nhau cho các phân cấp test phức tạp.
Feature test nên chiếm đa số trong test suite Laravel. Chúng phát hiện các bug tích hợp mà unit test bỏ lỡ, như middleware route không đúng, quy tắc validation thiếu, hoặc quan hệ Eloquent bị hỏng. Quy tắc chung: nếu code chạm vào database, tầng HTTP, hoặc facade, hãy viết feature test.
Chiến Lược Mocking Với Facade và Mockery
Mocking trong kiểm thử Laravel cô lập code đang test khỏi các dependency bên ngoài. Các facade Laravel cung cấp implementation fake tích hợp cho queue, event, notification, mail và storage. Mockery xử lý phần còn lại.
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Queue;
use App\Mail\OrderConfirmation;
use App\Jobs\ProcessPayment;
it('dispatches payment job and sends confirmation email', function () {
// Fake both Mail and Queue facades
Mail::fake();
Queue::fake();
$user = User::factory()->create();
$order = Order::factory()->for($user)->create([
'total' => 99.99,
'status' => 'pending',
]);
// Act: confirm the order via HTTP
$this->actingAs($user)
->postJson("/api/orders/{$order->id}/confirm")
->assertOk();
// Assert: payment job was dispatched with correct amount
Queue::assertPushed(ProcessPayment::class, function ($job) use ($order) {
return $job->order->id === $order->id
&& $job->order->total === 99.99;
});
// Assert: confirmation email was sent to the user
Mail::assertSent(OrderConfirmation::class, function ($mail) use ($user) {
return $mail->hasTo($user->email);
});
});Facade fake chặn các lệnh gọi ở tầng framework, ngăn email thực sự được gửi hoặc job được dispatch. Các assertion dựa trên closure xác minh dữ liệu chính xác được truyền cho từng component.
Tránh mock các class domain nội bộ. Mock ở ranh giới: API bên thứ ba, mail, queue, filesystem. Mock quá mức làm test dễ vỡ và gắn chặt với chi tiết implementation.
Với các dependency không phải facade, inject qua constructor và sử dụng Mockery:
use App\Services\PaymentGateway;
use App\Services\StripeClient;
it('charges the customer through the payment gateway', function () {
// Create a mock of the Stripe client
$stripeClient = Mockery::mock(StripeClient::class);
$stripeClient->shouldReceive('charge')
->once()
->with('cus_abc123', 5000, 'usd')
->andReturn(['status' => 'succeeded', 'id' => 'ch_xyz']);
// Bind the mock in the container
$this->app->instance(StripeClient::class, $stripeClient);
$gateway = app(PaymentGateway::class);
$result = $gateway->processCharge('cus_abc123', 50.00);
expect($result['status'])->toBe('succeeded');
});Binding mock với $this->app->instance() thay thế implementation thực trong suốt thời gian test. Mockery xác minh rằng charge được gọi đúng một lần với các đối số mong đợi.
Architecture Testing Với Preset Pest
Pest 5 bao gồm architecture testing để thực thi các quy tắc cấu trúc trong toàn bộ codebase. Các test này chạy dựa trên AST, không phải runtime, giúp chúng cực kỳ nhanh.
arch('controllers do not use Eloquent directly')
->expect('App\Http\Controllers')
->not->toUse('Illuminate\Database\Eloquent');
arch('services are final classes')
->expect('App\Services')
->toBeFinal();
arch('no debugging functions in production code')
->expect(['dd', 'dump', 'var_dump', 'ray'])
->not->toBeUsed();Quy tắc đầu tiên ngăn controller truy vấn database trực tiếp, thực thi pattern service layer. Quy tắc thứ hai đảm bảo service không thể được extend, giảm độ phức tạp kế thừa. Quy tắc thứ ba phát hiện các statement debug còn sót trước khi chúng đến production.
Các preset dành riêng cho Laravel cũng có sẵn:
arch()->preset()->laravel();
arch()->preset()->security();
arch()->preset()->php();Ba dòng này thực thi hàng chục quy tắc: model extend đúng base class, controller không chứa business logic, không có hàm không an toàn như eval() hoặc md5() để hash, và các quy ước PHP chuẩn được tuân thủ.
Sẵn sàng chinh phục phỏng vấn Laravel?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Mutation Testing Để Xác Minh Chất Lượng Test
Code coverage đo các dòng nào được thực thi trong test. Mutation testing đi xa hơn: nó sửa đổi source code và kiểm tra xem test có phát hiện thay đổi không. Nếu một mutation sống sót, test suite có lỗ hổng.
# Run mutation testing on a specific class
php artisan test --mutate --class=App\\Services\\PriceCalculatorPest 5 giới thiệu các mutation như thay đổi > thành >=, xóa statement return, và đảo điều kiện boolean. Mutation score dưới 80% thường cho thấy test xác minh output mà không kiểm tra các trường hợp biên.
// Example: this test has high coverage but low mutation score
it('calculates shipping cost', function () {
$cost = calculateShipping(weight: 5.0, zone: 'domestic');
// Only checks that the result is numeric
expect($cost)->toBeFloat();
});
// Improved: catches mutations by asserting the exact value
it('calculates domestic shipping for 5kg package', function () {
$cost = calculateShipping(weight: 5.0, zone: 'domestic');
// Exact assertion catches operator and value mutations
expect($cost)->toBe(12.50);
});Test đầu tiên vẫn pass ngay cả khi logic tính toán hoàn toàn sai, miễn là nó trả về float. Test thứ hai fail ngay lập tức khi mutation thay đổi công thức. Các assertion cụ thể tạo ra mutation score cao hơn.
Pattern Kiểm Thử Database và Factory
Model factory Laravel tạo dữ liệu test thực tế mà không cần xây dựng array thủ công. Pest 5 kết hợp với factory tạo ra setup dữ liệu dễ đọc và dễ bảo trì.
use App\Models\Article;
use App\Models\User;
it('publishes a draft article and updates the timestamp', function () {
$author = User::factory()->create(['role' => 'editor']);
$article = Article::factory()
->for($author, 'author')
->draft()
->create(['title' => 'Testing Best Practices']);
$this->actingAs($author)
->patchJson("/api/articles/{$article->id}/publish")
->assertOk()
->assertJsonPath('data.status', 'published');
$article->refresh();
expect($article->status)->toBe('published')
->and($article->published_at)->not->toBeNull()
->and($article->published_at->isToday())->toBeTrue();
});Factory state draft() đặt giá trị mặc định cho bài viết chưa xuất bản. Các assertion expect() được chain với ->and() đọc như ngôn ngữ tự nhiên và fail với thông báo mô tả rõ ràng.
Chạy php artisan test --parallel để thực thi test trên nhiều process. Laravel tự động tạo database test riêng cho mỗi process, ngăn xung đột dữ liệu. Time-balanced sharding của Pest 5 phân phối test theo thời gian thực thi thực tế thay vì số lượng, đảm bảo mọi CI shard kết thúc cùng lúc.
Câu Hỏi Phỏng Vấn Kỹ Thuật Laravel Testing
Các buổi phỏng vấn kỹ thuật cho vị trí Laravel thường xuyên kiểm tra kiến thức testing. Dưới đây là các câu hỏi xuất hiện nhiều nhất, cùng với những điểm mà câu trả lời tốt cần đề cập.
Sự khác biệt giữa fake(), mock() và spy() trong kiểm thử Laravel là gì?
Facade fake() thay thế toàn bộ facade bằng implementation in-memory (Mail::fake, Queue::fake). mock() qua Mockery đặt kỳ vọng trước khi thực thi và fail nếu không đáp ứng. spy() ghi lại các tương tác và cho phép assertion sau khi thực thi, mà không đặt kỳ vọng trước. Lựa chọn phụ thuộc vào việc test cần xác minh hành vi (mock), ghi lại tương tác (spy), hay ngăn side effect (fake).
RefreshDatabase khác DatabaseTransactions như thế nào?
RefreshDatabase chạy migration một lần và bọc mỗi test trong transaction. DatabaseTransactions giả định database đã có schema đúng và chỉ bọc test trong transaction. RefreshDatabase an toàn hơn cho pipeline CI nơi database có thể chưa tồn tại. DatabaseTransactions nhanh hơn khi schema được đảm bảo là hiện tại.
Khi nào nên ưu tiên feature test hơn unit test?
Feature test nên bao phủ bất kỳ code nào tương tác với tầng HTTP, database, hoặc service Laravel. Unit test được dành cho các pure function và value object không có dependency framework. Trong ứng dụng Laravel điển hình, feature test nhiều hơn unit test với tỷ lệ khoảng 3:1 hoặc cao hơn. Điều này phản ánh thực tế rằng hầu hết code Laravel vốn đã tích hợp với framework.
Test Impact Analysis cải thiện hiệu suất CI như thế nào?
TIA ghi lại test nào chạm vào file source nào trong lần chạy đầu tiên. Trong các lần chạy tiếp theo, Pest chỉ thực thi các test bị ảnh hưởng bởi file đã thay đổi và phát lại kết quả đã cache cho các test không thay đổi. Các suite lớn mất nhiều phút có thể hoàn thành trong vài giây. Đánh đổi: TIA yêu cầu coverage driver (PCOV hoặc Xdebug) để xây dựng bản đồ dependency, và lần chạy đầu tiên lâu hơn bình thường.
Mutation testing cải thiện chất lượng test như thế nào so với code coverage?
Code coverage đo các đường thực thi. Một test có thể đạt coverage 100% bằng cách gọi mọi method mà không assert gì có ý nghĩa. Mutation testing sửa đổi source code (thay đổi operator, xóa return, đảo boolean) và xác minh rằng ít nhất một test fail. Các mutation sống sót cho thấy assertion quá lỏng hoặc thiếu hoàn toàn. Chạy php artisan test --mutate tạo ra phần trăm mutation score cùng với coverage tiêu chuẩn.
Để tìm thêm câu hỏi phỏng vấn Laravel, ngân hàng câu hỏi SharpSkill bao gồm authentication, pattern service container, quan hệ Eloquent, và kiến trúc queue.
Kiểm Thử HTTP Response và JSON Assertion
Các helper kiểm thử HTTP của Laravel xác minh status code, header, cấu trúc JSON và target redirect. Kết hợp với Pest, chúng tạo thành các integration test ngắn gọn.
use App\Models\User;
describe('API Authentication', function () {
it('rejects unauthenticated requests with 401', function () {
$this->getJson('/api/profile')
->assertUnauthorized();
});
it('returns the authenticated user profile', function () {
$user = User::factory()->create([
'name' => 'John Doe',
'email' => 'john@example.com',
]);
$this->actingAs($user)
->getJson('/api/profile')
->assertOk()
->assertJson([
'data' => [
'name' => 'John Doe',
'email' => 'john@example.com',
],
]);
});
it('validates required fields on registration', function () {
$this->postJson('/api/register', [])
->assertUnprocessable()
->assertJsonValidationErrors(['name', 'email', 'password']);
});
});Khối describe nhóm các test liên quan đến authentication. Mỗi tên test mô tả hành vi mong đợi, không phải implementation. Method assertJsonValidationErrors kiểm tra rằng các field cụ thể có thông báo lỗi validation.
Nguồn Tham Khảo
- Pest 5 Released bởi Laravel News, công bố công cụ TIA, plugin Agent, và Evals
- Pest 5 Now Available, tài liệu chính thức với yêu cầu và tính năng mới
- What We Know About Laravel 13, đề cập PHP Attributes, AI SDK, và bản phát hành tháng 3/2026
- PHPUnit 13 Release Announcement, chi tiết các assertion mới và deprecation
Những Điều Cần Nhớ Về Laravel Testing Với Pest 5
- Pest 5 với Laravel 13 loại bỏ boilerplate thông qua API cấu hình fluent, chain
expect(), và tự động phát hiện test - Công cụ TIA chỉ chạy lại các test bị ảnh hưởng, giảm thời gian thực thi suite lớn từ phút xuống giây mà không hy sinh độ chính xác coverage
- Feature test nên tạo thành cốt lõi của test suite Laravel, với unit test được dành cho business logic độc lập
- Facade fake (
Mail::fake(),Queue::fake()) xử lý mocking ở tầng framework, trong khi Mockery xử lý dependency bên thứ ba được inject qua container - Architecture test thực thi các quy tắc cấu trúc (không có Eloquent trong controller, không có hàm debug) mà không có overhead runtime
- Mutation testing với
--mutatephát hiện các assertion yếu mà code coverage đơn thuần bỏ lỡ - Factory state và các assertion
expect()->and()được chain giữ cho setup dữ liệu test dễ đọc và các assertion cụ thể - Để chuẩn bị phỏng vấn Laravel, hiểu mock/fake/spy, hành vi
RefreshDatabase, TIA, và mutation testing cho thấy sự trưởng thành về testing vượt xa coverage cơ bản
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Bạn có tìm ra lỗi trong Laravel không?
Một đoạn mã thật, một lỗi ẩn, mỗi ngày một lượt. Không cần tài khoản để thử.

Viết bởi
Anthony Fillion-MailletNgười sáng lập SharpSkill
Lập trình viên fullstack hơn 10 năm. Anh điều hành SharpSkill và chịu trách nhiệm về mọi nội dung đăng tại đây.
Cập nhật ngày 2 tháng 9, 2026
Thẻ
Chia sẻ
Bài viết liên quan

Câu Hỏi Phỏng Vấn PHP Laravel Developer 2026: Hướng Dẫn Chuẩn Bị Toàn Diện
Hướng dẫn toàn diện để chuẩn bị cho buổi phỏng vấn PHP Laravel developer năm 2026. Bao gồm các câu hỏi kỹ thuật về Eloquent ORM, Service Container, authentication, queue và testing.

Laravel 12 năm 2026: Tính năng mới, Starter Kit và Câu hỏi phỏng vấn
Laravel 12 mang đến các starter kit được thiết kế lại với React 19, Vue 3, Livewire 4 và WorkOS AuthKit. Hướng dẫn đầy đủ về tính năng mới, lộ trình nâng cấp và các câu hỏi phỏng vấn trọng tâm cho năm 2026.

Cau Hoi Phong Van Laravel va PHP: Top 25 Nam 2026
25 cau hoi phong van Laravel va PHP thuong gap nhat. Service Container, Eloquent ORM, middleware, queues va trien khai production voi dap an chi tiet kem code mau.