Pernah nggak, kamu sudah deploy aplikasi Laravel dengan penuh percaya diri — lalu tiba-tiba ada bug konyol yang bikin fitur login mati total? ๐ญ Kalau pernah, selamat datang di klub yang nggak mau ada anggota baru. Solusinya satu kata: testing. Di artikel ke-42 dari seri 50 Artikel Belajar Laravel ini, kita akan bedah tuntas cara kerja testing Laravel PHPUnit — mulai dari apa itu testing, perbedaan Unit Test vs Feature Test, sampai kamu bisa langsung nulis test case sendiri. Anggap ini sebagai "helm pengaman" sebelum kamu ngebut di jalan production.
Testing dalam pengembangan software adalah proses memverifikasi bahwa kode yang kamu tulis bekerja sesuai ekspektasi. Laravel hadir dengan dukungan PHPUnit secara built-in, artinya kamu tidak perlu install tool tambahan — tinggal tulis, jalankan, dan periksa hasilnya.
๐ก️ Mengapa Testing Laravel PHPUnit Itu Wajib Dipelajari?
Bayangkan kamu membangun gedung bertingkat. Sebelum lantai 10 dibangun, insinyur pasti ngecek dulu apakah fondasi dan tiap lantai di bawahnya kokoh. Nah, testing di software itu fungsinya persis sama — memastikan setiap "lantai" (fungsi/fitur) kamu aman sebelum menambahkan yang baru di atasnya.
Tanpa testing, setiap kali kamu menambah fitur baru, kamu harus tes ulang semua fitur lama secara manual. Itu membuang waktu, tenaga, dan bikin developer cepat burnout. Dengan testing Laravel PHPUnit, proses itu bisa diotomasi.
Menurut studi IBM, biaya memperbaiki bug yang ditemukan setelah production bisa 6x lebih mahal dibanding memperbaikinya saat development. Testing = investasi, bukan pemborosan waktu!
๐ Perbandingan: Tanpa Testing vs Dengan Testing
⚡ Perbedaan Unit Test dan Feature Test di Laravel PHPUnit
Laravel menyediakan dua jenis test utama: Unit Test dan Feature Test. Analoginya begini — Unit Test itu seperti ngecek apakah masing-masing baut dan mur di mobilmu berfungsi sendiri-sendiri. Sedangkan Feature Test itu seperti test drive — kamu menguji apakah seluruh mobil bisa berjalan dari A ke B dengan lancar.
๐ Analisis: Unit Test vs Feature Test
- Menguji satu fungsi/method terisolasi
- Tidak melibatkan database atau HTTP
- Eksekusi sangat cepat
- Folder:
tests/Unit/
- Menguji alur lengkap (HTTP request → response)
- Melibatkan database, routes, middleware
- Eksekusi lebih lambat, tapi lebih komprehensif
- Folder:
tests/Feature/
๐งช Cara Menulis Unit Test di Laravel — Step by Step
Oke, mari langsung praktik! Kita akan buat Unit Test sederhana untuk sebuah class helper yang bertugas menghitung diskon produk.
Buat file app/Helpers/PriceCalculator.php berisi logika perhitungan diskon.
<?php
namespace App\Helpers;
class PriceCalculator
{
public function calculateDiscount(float $price, float $discountPercent): float
{
if ($discountPercent < 0 || $discountPercent > 100) {
throw new \InvalidArgumentException('Diskon harus antara 0-100%');
}
return $price - ($price * $discountPercent / 100);
}
}
php artisan make:test PriceCalculatorTest --unit
File akan dibuat di tests/Unit/PriceCalculatorTest.php
<?php
namespace Tests\Unit;
use App\Helpers\PriceCalculator;
use PHPUnit\Framework\TestCase;
class PriceCalculatorTest extends TestCase
{
protected PriceCalculator $calculator;
protected function setUp(): void
{
parent::setUp();
$this->calculator = new PriceCalculator();
}
/** @test */
public function it_calculates_discount_correctly(): void
{
$result = $this->calculator->calculateDiscount(100000, 20);
$this->assertEquals(80000, $result);
}
/** @test */
public function it_returns_full_price_when_discount_is_zero(): void
{
$result = $this->calculator->calculateDiscount(100000, 0);
$this->assertEquals(100000, $result);
}
/** @test */
public function it_throws_exception_for_invalid_discount(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->calculator->calculateDiscount(100000, 150);
}
}
php artisan test --filter PriceCalculatorTest
PASS Tests\Unit\PriceCalculatorTest ✓ it calculates discount correctly 0.08s ✓ it returns full price when discount is zero 0.01s ✓ it throws exception for invalid discount 0.01s Tests: 3 passed (3 assertions) Duration: 0.15s
Nama method test yang deskriptif seperti it_calculates_discount_correctly() jauh lebih bermanfaat daripada test1(). Anggap nama test sebagai "spesifikasi hidup" dari kode kamu!
๐ Menulis Feature Test: Simulasi HTTP Request Nyata
Sekarang kita naik level dengan Feature Test. Kita akan mensimulasikan request ke endpoint API dan memverifikasi response-nya. Contoh kasus: testing endpoint login menggunakan testing Laravel PHPUnit dengan database testing menggunakan Refresh Database.
php artisan make:test AuthTest
Tanpa flag --unit, file akan dibuat di tests/Feature/ secara default.
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AuthTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function user_can_login_with_correct_credentials(): void
{
// Arrange: buat user menggunakan factory
$user = User::factory()->create([
'email' => 'test@example.com',
'password' => bcrypt('password123'),
]);
// Act: kirim POST request ke endpoint login
$response = $this->postJson('/api/login', [
'email' => 'test@example.com',
'password' => 'password123',
]);
// Assert: periksa response
$response->assertStatus(200)
->assertJsonStructure(['token', 'user']);
}
/** @test */
public function user_cannot_login_with_wrong_password(): void
{
User::factory()->create([
'email' => 'test@example.com',
'password' => bcrypt('password123'),
]);
$response = $this->postJson('/api/login', [
'email' => 'test@example.com',
'password' => 'salahpassword',
]);
$response->assertStatus(422);
}
/** @test */
public function authenticated_user_can_access_profile(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)
->getJson('/api/profile');
$response->assertStatus(200)
->assertJson(['email' => $user->email]);
}
}
Trait RefreshDatabase akan me-reset database ke kondisi awal setelah setiap test berjalan. Ini memastikan setiap test case berjalan dalam kondisi bersih dan tidak saling mempengaruhi satu sama lain.
Pastikan kamu menggunakan database testing terpisah (misalnya SQLite in-memory) agar data production kamu tidak tersentuh saat menjalankan test. Konfigurasikan di file phpunit.xml atau .env.testing.
๐ Best Practices Testing Laravel PHPUnit yang Wajib Kamu Tahu
Menulis test itu seni, bukan sekadar formalitas. Ada beberapa prinsip yang membuat test kamu benar-benar bermanfaat, bukan sekadar menambah jumlah file di folder tests/.
Setiap test harus mengikuti pola Arrange → Act → Assert. Buat datanya, jalankan fungsinya, periksa hasilnya.
Setiap method test hanya menguji satu skenario. Jangan gabungkan 5 assertion berbeda dalam satu test.
Gunakan Laravel Factory untuk generate data dummy. Lebih bersih daripada hardcode data di setiap test.
Jangan hanya test "happy path". Test juga input kosong, nilai ekstrem, dan kondisi error yang mungkin terjadi.
Integrasikan testing Laravel PHPUnit kamu ke pipeline CI/CD (GitHub Actions, GitLab CI, dll). Setiap push ke repository akan otomatis menjalankan semua test — aplikasi yang lolos CI dijamin jauh lebih stabil di production.
Kesimpulan
Kita sudah menjelajahi dunia testing Laravel PHPUnit dari awal sampai akhir. Intinya:
- Testing bukan opsional — di lingkungan profesional, ini adalah standar minimum.
- Unit Test menguji fungsi terisolasi dengan cepat; Feature Test menguji alur lengkap aplikasi.
- Ikuti prinsip AAA (Arrange-Act-Assert) dan beri nama test yang deskriptif.
- Gunakan
RefreshDatabaseuntuk Feature Test agar data selalu bersih. - Integrasikan ke CI/CD untuk otomasi yang sesungguhnya! ๐
Artikel ini adalah bagian dari 50 Artikel Belajar Laravel — seri terlengkap dalam bahasa Indonesia!
No comments:
Post a Comment