🧪

Feature Tests

HTTP Tests

php artisan make:test PostControllerTest
<?php
// tests/Feature/PostControllerTest.php

namespace Tests\Feature;

use App\Models\Post;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class PostControllerTest extends TestCase
{
    use RefreshDatabase;

    public function test_can_list_posts(): void
    {
        Post::factory()->count(5)->create();

        $response = $this->getJson('/api/posts');

        $response->assertStatus(200)
            ->assertJsonCount(5, 'data')
            ->assertJsonStructure([
                'data' => [
                    '*' => ['id', 'title', 'slug', 'created_at']
                ]
            ]);
    }

    public function test_can_create_post(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)
            ->postJson('/api/posts', [
                'title' => 'Test Post',
                'content' => 'Test content here',
            ]);

        $response->assertStatus(201)
            ->assertJson([
                'data' => [
                    'title' => 'Test Post',
                ]
            ]);

        $this->assertDatabaseHas('posts', [
            'title' => 'Test Post',
            'user_id' => $user->id,
        ]);
    }

    public function test_guest_cannot_create_post(): void
    {
        $response = $this->postJson('/api/posts', [
            'title' => 'Test Post',
            'content' => 'Test content',
        ]);

        $response->assertStatus(401);
    }

    public function test_validation_errors(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)
            ->postJson('/api/posts', [
                'title' => '', // Empty - should fail
            ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['title', 'content']);
    }
}
🔬

Unit Tests

Test Services và Models

php artisan make:test Services/OrderServiceTest --unit
<?php
// tests/Unit/Services/OrderServiceTest.php

namespace Tests\Unit\Services;

use App\Models\Order;
use App\Models\Product;
use App\Services\OrderService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class OrderServiceTest extends TestCase
{
    use RefreshDatabase;

    private OrderService $orderService;

    protected function setUp(): void
    {
        parent::setUp();
        $this->orderService = new OrderService();
    }

    public function test_calculate_total(): void
    {
        $items = [
            ['price' => 100, 'quantity' => 2],
            ['price' => 50, 'quantity' => 3],
        ];

        $total = $this->orderService->calculateTotal($items);

        $this->assertEquals(350, $total);
    }

    public function test_apply_discount(): void
    {
        $total = 1000;
        $discountPercent = 10;

        $result = $this->orderService->applyDiscount($total, $discountPercent);

        $this->assertEquals(900, $result);
    }

    public function test_free_shipping_over_500(): void
    {
        $this->assertTrue($this->orderService->hasFreeShipping(600));
        $this->assertFalse($this->orderService->hasFreeShipping(400));
    }
}

Chạy Tests

# Chạy tất cả tests
php artisan test

# Chạy test cụ thể
php artisan test --filter=PostControllerTest

# Chạy với coverage
php artisan test --coverage

# Parallel testing (nhanh hơn)
php artisan test --parallel
💡 CI/CD: Chạy php artisan test trong pipeline để đảm bảo code quality.
← Bài 10: Factories Bài 12: Testing Nâng Cao →