Testing — Laravel

Laravel menyediakan tools testing yang powerful out of the box. Feature test (test HTTP endpoint): class UserTest extends TestCase { use RefreshDatabase…

Laravel menyediakan tools testing yang powerful out of the box.

Feature test (test HTTP endpoint):

class UserTest extends TestCase
{
    use RefreshDatabase;

    public function test_can_list_users(): void
    {
        User::factory()->count(3)->create();

        $response = $this->getJson("/api/users");

        $response->assertOk()
            ->assertJsonCount(3, "data");
    }

    public function test_can_create_user(): void
    {
        $response = $this->postJson("/api/users", [
            "name" => "Budi",
            "email" => "[email protected]",
        ]);

        $response->assertCreated()
            ->assertJsonPath("data.name", "Budi");

        $this->assertDatabaseHas("users", [
            "email" => "[email protected]",
        ]);
    }

    public function test_validation_fails_without_name(): void
    {
        $response = $this->postJson("/api/users", [
            "email" => "[email protected]",
        ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(["name"]);
    }
}

Factory (generate test data):

class UserFactory extends Factory
{
    public function definition(): array
    {
        return [
            "name" => fake()->name(),
            "email" => fake()->unique()->safeEmail(),
            "role" => "user",
        ];
    }

    public function admin(): static
    {
        return $this->state(["role" => "admin"]);
    }
}

// Penggunaan:
User::factory()->create();           // 1 user biasa
User::factory()->admin()->create();  // 1 admin
User::factory()->count(10)->create(); // 10 user

Fakes — Test Tanpa Side Effect ke Dunia Luar

Test tidak boleh benar-benar kirim email, panggil API eksternal, atau mendispatch job ke queue — itu bikin test lambat, flaky, dan kadang bikin biaya (kirim SMS beneran, hit endpoint production). Laravel kasih fake() helper untuk mencegah side-effect.

HTTP Client fake — tahan request ke service eksternal:

use Illuminate\Support\Facades\Http;

public function test_sync_dengan_payment_gateway(): void
{
    Http::fake([
        "api.midtrans.com/v2/charge" => Http::response([
            "status_code" => "200",
            "transaction_id" => "abc-123",
        ], 200),
    ]);

    $response = $this->postJson("/api/orders", ["amount" => 100000]);

    $response->assertCreated();
    Http::assertSent(function ($request) {
        return $request->url() === "https://api.midtrans.com/v2/charge"
            && $request["gross_amount"] === 100000;
    });
}

Mail fake — test email dikirim tanpa beneran mengirim:

use Illuminate\Support\Facades\Mail;
use App\Mail\WelcomeEmail;

public function test_send_welcome_email_on_signup(): void
{
    Mail::fake();

    $this->postJson("/api/register", [
        "email" => "[email protected]",
        "password" => "secret123",
    ]);

    Mail::assertSent(WelcomeEmail::class, function ($mail) {
        return $mail->hasTo("[email protected]");
    });
}

Event fake — test event di-dispatch tanpa trigger listener:

use Illuminate\Support\Facades\Event;
use App\Events\OrderPlaced;

public function test_order_placed_event_fired(): void
{
    Event::fake([OrderPlaced::class]);

    $this->postJson("/api/orders", [...]);

    Event::assertDispatched(OrderPlaced::class, fn ($event) => $event->order->amount > 0);
}

Queue fake — test job di-push ke queue tanpa benar-benar eksekusi worker:

use Illuminate\Support\Facades\Queue;
use App\Jobs\ProcessVideoJob;

public function test_video_upload_queues_processing(): void
{
    Queue::fake();

    $this->postJson("/api/videos", [...]);

    Queue::assertPushed(ProcessVideoJob::class);
    Queue::assertPushedOn("videos", ProcessVideoJob::class);  // queue name
}

Storage fake — test upload file tanpa benar-benar menulis ke disk:

use Illuminate\Support\Facades\Storage;
use Illuminate\Http\UploadedFile;

public function test_upload_avatar(): void
{
    Storage::fake("avatars");

    $file = UploadedFile::fake()->image("avatar.jpg", 500, 500);

    $this->postJson("/api/avatar", ["file" => $file]);

    Storage::disk("avatars")->assertExists("avatar.jpg");
}

Cheatsheet Fake Assertions

Http::assertSent / assertNotSent / assertSentCount
Mail::assertSent / assertNotSent / assertQueued / assertNothingSent
Event::assertDispatched / assertNotDispatched / assertDispatchedTimes
Queue::assertPushed / assertNotPushed / assertPushedOn / assertNothingPushed
Notification::assertSentTo / assertNothingSent
Storage::disk("x")->assertExists / assertMissing

Tips Testing Produktif

Yang akan kamu pelajari