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
RefreshDatabasetrait — auto-rollback per test supaya tidak saling bocor$this->actingAs($user)— login sebagai user tertentu untuk test authenticated endpoint- Factory states (
->admin(),->unverified()) — sebut intent, bukan detail - Group assertion dengan
$response->assertOk()->assertJsonCount(3, "data")— readable - Test behavior bukan implementation — test "user bisa buat order" bukan "method createOrder di-call"