PHPUnit adalah framework testing standar untuk PHP: kamu menulis method yang menjalankan kodemu, lalu menyatakan hasil yang kamu harapkan lewat assertion (pernyataan "harusnya begini"). Laravel sudah memasangnya sejak project dibuat. Bayangin petugas QC di pabrik biskuit: tiap biskuit dicocokkan dengan daftar "harusnya begini". Cocok, lanjut. Gak cocok, disisihkan dan dicatat alasannya. PHPUnit juga begitu: dia mencetak titik untuk tiap test yang cocok, huruf F untuk yang gagal, lalu menulis alasannya.
🧪 Tebakan cepat:
$this->assertEquals(5, '5')dan$this->assertSame(5, '5'). Mana yang lulus? Tebak dulu, jawabannya ada di bagian "assertEquals atau assertSame?".
Test pertama: class, method, assert
Kode yang mau dites ada di app/Calculator.php:
<?php
namespace App;
class Calculator
{
public static function add($a, $b)
{
return $a + $b;
}
}
Test-nya di tests/Unit/CalculatorTest.php:
<?php
namespace Tests\Unit;
use App\Calculator;
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase
{
public function test_add_dua_angka(): void
{
$this->assertEquals(5, Calculator::add(2, 3));
}
}
class CalculatorTest extends TestCase: satu class test, namanya diakhiriTest, mewarisiTestCasemilik PHPUnit.public function test_add_dua_angka(): void: tiap method yang namanya diawalitestadalah satu test. Method tanpa awalan itu gak dijalankan, kecuali diberi attribute#[Test].$this->assertEquals(5, Calculator::add(2, 3)): nilai yang diharapkan di depan, nilai yang benar-benar keluar di belakang. Kalau beda, test-nya gagal.
Menjalankan dan membaca hasilnya
Jalankan dari folder project dengan ./vendor/bin/phpunit (di Laravel juga bisa php artisan test). Kalau semua cocok:
PHPUnit 12.5.14 by Sebastian Bergmann and contributors.
Runtime: PHP 8.4.6
Configuration: /home/budi/kalkulator/phpunit.xml
. 1 / 1 (100%)
Time: 00:00.002, Memory: 26.50 MB
OK (1 test, 1 assertion)
Kalau add keliru menyambung teks (return $a . $b;, hasilnya '23'):
PHPUnit 12.5.14 by Sebastian Bergmann and contributors.
Runtime: PHP 8.4.6
Configuration: /home/budi/kalkulator/phpunit.xml
F 1 / 1 (100%)
Time: 00:00.003, Memory: 26.50 MB
There was 1 failure:
1) Tests\Unit\CalculatorTest::test_add_dua_angka
Failed asserting that '23' matches expected 5.
/home/budi/kalkulator/tests/Unit/CalculatorTest.php:12
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
- Satu karakter per test:
.lulus,Fassertion-nya gagal,Eada error (exception yang gak ditangkap). - Tiap kegagalan diberi nomor, nama test-nya, alasannya, dan baris assertion-nya.
- Baris terakhir merangkum: berapa test, berapa assertion, berapa yang gagal.
assertEquals atau assertSame?
Ini jawaban tebakannya: assertEquals(5, '5') lulus, assertSame(5, '5') gagal.
assertEqualsmembandingkan longgar, seperti==: angka5dan teks'5'dianggap sama.assertSamemembandingkan ketat, seperti===: nilainya dan tipenya harus sama. Pesannya:Failed asserting that '5' is identical to 5.
Bedanya kerasa di kasus nyata. round(2 + 3, 2) menghasilkan float 5.0. assertEquals(5, 5.0) lulus, tapi assertSame(5, 5.0) gagal dengan Failed asserting that 5.0 is identical to 5. Kalau tipe ikut penting, pakai assertSame.
Assertion lain yang sering dipakai
| Assertion | Lulus kalau | Pesan kalau gagal |
|---|---|---|
assertTrue($x) / assertFalse($x) |
$x persis true / false |
Failed asserting that false is true. |
assertNull($x) |
$x adalah null |
|
assertCount(3, $arr) |
isi array ada 3 | Failed asserting that actual size 2 matches expected size 3. |
assertContains('apel', $arr) |
array memuat 'apel' |
Failed asserting that an array contains 'apel'. |
assertArrayHasKey('nama', $arr) |
array punya key nama |
|
assertStringContainsString('Halo', $s) |
teks memuat Halo |
|
assertGreaterThan(5, $x) |
$x lebih besar dari 5 |
Failed asserting that 3 is greater than 5. |
assertInstanceOf(User::class, $u) |
$u objek User |
setUp(): disiapkan ulang sebelum tiap test
Kalau beberapa test butuh objek yang sama, siapkan di setUp(). PHPUnit memanggilnya sebelum tiap test, jadi tiap test dapat objek baru yang bersih.
class KeranjangTest extends TestCase
{
private Keranjang $keranjang;
protected function setUp(): void
{
parent::setUp();
$this->keranjang = new Keranjang();
}
protected function tearDown(): void
{
// bersihkan file atau koneksi kalau ada
parent::tearDown();
}
}
Urutan untuk dua test: setUp, test_satu, tearDown, lalu setUp, test_dua, tearDown. parent::setUp() jangan dibuang, karena TestCase (apalagi milik Laravel) menyiapkan banyak hal di situ.
Data provider: satu test, banyak data
Daripada menyalin test yang sama untuk tiap angka, pisahkan datanya ke method provider:
use PHPUnit\Framework\Attributes\DataProvider;
public static function angkaProvider(): array
{
return [
'dua' => [2, true],
'empat' => [4, false],
'tujuh' => [7, true],
'sembilan' => [9, false],
];
}
#[DataProvider('angkaProvider')]
public function test_is_prime(int $angka, bool $harusnya): void
{
$this->assertSame($harusnya, Calculator::isPrime($angka));
}
- Provider-nya
public staticdan mengembalikan array kasus. Tiap kasus berisi argumen untuk method test-nya:$angka, lalu$harusnya. #[DataProvider('angkaProvider')](attribute PHP 8) menyambungkan provider ke test. PHPUnit menjalankan test-nya sekali per kasus: empat kasus, empat test.- Kalau satu kasus gagal, namanya ikut dicetak:
Tests\Unit\CalculatorTest::test_is_prime@sembilan with data (9, false). Itu gunanya key'sembilan'.
Menguji exception
public function test_bagi_nol_ditolak(): void
{
$this->expectException(InvalidArgumentException::class);
Calculator::bagi(10, 0);
}
expectException ditulis sebelum kode yang melempar. Test lulus kalau exception itu benar-benar dilempar. Kalau gak ada yang dilempar: Failed asserting that exception of type "InvalidArgumentException" is thrown.
Di latihan: tiru assertion-nya sendiri
Sandbox latihan menjalankan PHP biasa, tanpa PHPUnit. Jadi kamu menulis pemeriksaannya sendiri dan mencetak hasilnya:
function assertEquals($expected, $actual): string
{
return $expected === $actual ? "PASS" : "FAIL";
}
echo "1) " . assertEquals(5, 2 + 3) . "\n"; // 1) PASS
echo "3) " . assertEquals(10, 3 * 3) . "\n"; // 3) FAIL
- Bandingkan
$expected === $actual, supaya tipe ikut dicek sepertiassertSame. - Untuk menguji
Calculator::add, simpan dulu ke variabel, lalu cetak hasil perbandingannya:$actual = Calculator::add(2, 3);laluecho "assertEquals(5, Calculator::add(2, 3)): " . ($expected === $actual ? "PASS" : "FAIL") . "\n"; - Untuk data provider, tulis
angkaProvider()yang mengembalikan array kasus, dan function test dengan attribute#[DataProvider('angkaProvider')]tepat di atasnya. Gak ada PHPUnit yang membaca attribute itu, jadi kamu sendiri yang memanggil test-nya per kasus,foreach (angkaProvider() as $kasus) { echo testIsPrime(...$kasus) . "\n"; }, dan mencetak satu baris per kasus, misalnyaassertTrue(isPrime(2)): PASS.
⚠️ Jebakan yang sering ketemu
- Urutan argumen terbalik.
assertEquals($hasil, 5)tetap jalan, tapi pesannya jadi menyesatkan: "matches expected" menunjuk nilai yang salah. Yang diharapkan selalu di depan. assertEqualsmeloloskan tipe yang salah.'5'dan5.0dianggap sama dengan5. PakaiassertSamekalau tipe penting.- Method test tanpa awalan
test.public function penjumlahan()gak dijalankan sama sekali, dan gak ada pesan apa pun. - Annotation lama
@dataProviderdi komentar. PHPUnit 12 gak membacanya lagi, jadi test-nya dipanggil tanpa argumen dan berhenti denganArgumentCountError. Pakai attribute#[DataProvider('...')], dan provider-nya harusstatic. expectExceptionsesudah kodenya. Exception-nya keburu dilempar, jadi test-nyaE(error), bukan lulus.
TL;DR: Test PHPUnit adalah class ...Test extends TestCase dengan method test_...(): void yang memanggil $this->assert...(diharapkan, sebenarnya). Jalankan dengan ./vendor/bin/phpunit: . lulus, F gagal, E error. assertEquals membandingkan longgar (==), assertSame ketat (===, tipe ikut dicek). Ada juga assertTrue, assertFalse, assertCount, assertContains. setUp() jalan sebelum tiap test. #[DataProvider('namaProvider')] menjalankan satu test untuk tiap kasus dari provider public static. expectException(InvalidArgumentException::class) ditulis sebelum kode yang melempar. Di sandbox latihan, tiru assertion-nya dengan === lalu echo PASS atau FAIL.