Laravel – Testing & TDD in Practice

2 min read


Vì sao Testing trong Laravel quan trọng?

Rất nhiều project Laravel bỏ qua testing ở giai đoạn đầu. Nhưng khi hệ thống lớn dần:

  • Refactor trở nên nguy hiểm
  • Fix bug dễ sinh bug mới
  • Onboard dev mới mất nhiều thời gian

Testing giúp bạn:

  • Tự tin thay đổi code
  • Giảm regression
  • Giữ chất lượng code ổn định

Tài liệu chính thức:
https://laravel.com/docs/testing


1️⃣ Cấu trúc Testing trong Laravel

Laravel được build trên PHPUnit và có sẵn cấu trúc:

tests/
 ├── Feature/
 ├── Unit/

Unit Test

  • Test logic nhỏ
  • Không test HTTP
  • Chạy nhanh

Feature Test

  • Test request/response
  • Test API
  • Test full flow

2️⃣ Viết Unit Test cho Service

Giả sử bạn có service:

class CalculateDiscount
{
    public function execute(int $price): int
    {
        return $price * 0.9;
    }
}

Tạo test:

php artisan make:test CalculateDiscountTest --unit

Viết test:

public function test_it_calculates_discount_correctly()
{
    $service = new CalculateDiscount();    $result = $service->execute(100);    $this->assertEquals(90, $result);
}

Unit test nên:

  • Không phụ thuộc database
  • Không call API ngoài
  • Không gửi mail thật

3️⃣ Feature Test cho API

Ví dụ test endpoint đăng ký user:

public function test_user_can_register()
{
    $response = $this->postJson('/api/register', [
        'name' => 'John',
        'email' => 'john@example.com',
        'password' => 'password'
    ]);    $response->assertStatus(201);    $this->assertDatabaseHas('users', [
        'email' => 'john@example.com'
    ]);
}

Laravel cung cấp nhiều helper:

  • assertStatus
  • assertJson
  • assertDatabaseHas
  • assertSee

Giúp test rất rõ ràng và dễ đọc.


4️⃣ Database Testing với RefreshDatabase

Laravel hỗ trợ reset database tự động trong test.

use Illuminate\Foundation\Testing\RefreshDatabase;

Trait này sẽ:

  • Rollback transaction
    hoặc
  • Migrate lại database cho mỗi test

Đảm bảo mỗi test độc lập và không ảnh hưởng lẫn nhau.


5️⃣ Mock Dependency với Service Container

Nếu bạn đã áp dụng Dependency Injection, việc mock rất dễ.

$this->mock(PaymentService::class, function ($mock) {
    $mock->shouldReceive('charge')
         ->once()
         ->andReturn(true);
});

Laravel sử dụng Mockery phía dưới.

Tài liệu mocking:
https://laravel.com/docs/mocking

Mock giúp:

  • Không gọi API thật
  • Không gửi email thật
  • Không phụ thuộc service ngoài

6️⃣ Testing Authorization

Testing phân quyền cực kỳ quan trọng để tránh data leak.

Ví dụ:

public function test_user_cannot_update_other_user_post()
{
    $user = User::factory()->create();
    $otherUser = User::factory()->create();    $post = Post::factory()->create([
        'user_id' => $otherUser->id
    ]);    $this->actingAs($user)
         ->put("/posts/{$post->id}")
         ->assertStatus(403);
}

Nếu không test authorization, bạn có thể vô tình mở quyền sai trong production.


7️⃣ TDD trong Laravel

TDD (Test Driven Development) gồm 3 bước:

  1. Viết test trước
  2. Chạy test (fail)
  3. Viết code để pass
  4. Refactor

Laravel rất phù hợp cho TDD vì:

  • Có artisan tạo test nhanh
  • Có factory tạo data
  • Có HTTP test helper

Ví dụ tạo factory:

php artisan make:factory UserFactory

Factory giúp generate dữ liệu test dễ dàng.


8️⃣ Chạy Test trong CI

Trong production, test nên chạy tự động khi push code.

Chạy test:

php artisan test

Hoặc:

vendor/bin/phpunit

Tích hợp với:

  • GitHub Actions
  • GitLab CI
  • Azure Pipeline

Mỗi lần commit → test chạy → giảm rủi ro merge bug vào production.


Kết luận

Testing trong Laravel không hề phức tạp. Ngược lại, đây là một trong những hệ thống test dễ tiếp cận nhất trong PHP.

Để nâng level:

  • Viết unit test cho business logic
  • Viết feature test cho API
  • Test authorization
  • Mock dependency đúng cách
  • Tích hợp CI

Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *