Testing dengan PHPUnit

Mengapa menulis tes otomatis, memasang PHPUnit lewat Composer, menulis test case, assertion, data provider, menguji exception, dan test double (mock).

Part 20 dari 22 ± 50 menit Gratis

Mengapa menguji?

Tanpa tes, setiap perubahan kode adalah pertaruhan: kamu memperbaiki satu fitur dan tanpa sadar merusak yang lain. Tes otomatis adalah program kecil yang memeriksa program utamamu dalam hitungan detik, setiap kali kamu mau. Hasilnya: berani mengubah kode, bug cepat ketahuan, dan tes berfungsi sebagai dokumentasi cara pakai.

Memasang PHPUnit

composer require --dev phpunit/phpunit ^11
vendor/bin/phpunit --version

Struktur proyek yang umum:

proyek/
├── composer.json
├── phpunit.xml
├── src/Kalkulator.php
└── tests/KalkulatorTest.php

Contoh phpunit.xml minimal:

<phpunit bootstrap="vendor/autoload.php" colors="true">
    <testsuites>
        <testsuite name="app"><directory>tests</directory></testsuite>
    </testsuites>
</phpunit>

Tes pertamamu

Kode yang diuji (src/Kalkulator.php):

namespace App;

class Kalkulator
{
    public function bagi(int $a, int $b): float
    {
        if ($b === 0) {
            throw new \InvalidArgumentException('Pembagi tidak boleh nol');
        }
        return $a / $b;
    }
}

Tesnya (tests/KalkulatorTest.php):

namespace Tests;

use App\Kalkulator;
use PHPUnit\Framework\TestCase;

class KalkulatorTest extends TestCase
{
    public function testBagiMengembalikanHasilYangBenar(): void
    {
        $kalkulator = new Kalkulator();

        $hasil = $kalkulator->bagi(10, 4);

        $this->assertSame(2.5, $hasil);
    }

    public function testBagiDenganNolMelemparException(): void
    {
        $this->expectException(\InvalidArgumentException::class);

        (new Kalkulator())->bagi(1, 0);
    }
}

Jalankan: vendor/bin/phpunit. Titik hijau berarti lulus, F berarti gagal.

Aturan penamaan

  • Class tes berakhiran Test dan extends TestCase.
  • Method tes berawalan test (atau diberi atribut #[Test]), bertipe void, dan public.
  • Nama method menjelaskan perilaku yang diharapkan.

Pola Arrange – Act – Assert

TahapIsi
ArrangeSiapkan objek dan data
ActJalankan satu aksi yang diuji
AssertPeriksa hasilnya

Assertion yang sering dipakai

AssertionMemeriksa
assertSame($harapan, $aktual)Nilai dan tipe sama (===), pilihan utama
assertEquals(...)Nilai sama (==, longgar)
assertTrue / assertFalseBoolean
assertNull / assertNotNullNull
assertCount(n, $array)Jumlah elemen
assertContains($x, $array)Elemen ada di array
assertInstanceOf(Kelas::class, $obj)Tipe objek
expectException(Kelas::class)Pernyataan berikutnya harus melempar exception

Data provider: satu tes, banyak kasus

use PHPUnit\Framework\Attributes\DataProvider;

#[DataProvider('kasusBagi')]
public function testBagi(int $a, int $b, float $harapan): void
{
    $this->assertSame($harapan, (new Kalkulator())->bagi($a, $b));
}

public static function kasusBagi(): array
{
    return [
        'habis dibagi' => [10, 2, 5.0],
        'desimal'      => [1, 4, 0.25],
        'negatif'      => [-9, 3, -3.0],
    ];
}

setUp: persiapan sebelum tiap tes

private Kalkulator $kalkulator;

protected function setUp(): void
{
    $this->kalkulator = new Kalkulator();   // objek baru untuk setiap tes
}

Test double: mengganti dependency

Saat menguji Notifikasi yang memakai PengirimEmail (interface), kita tidak mau benar-benar mengirim email. Buat mock:

public function testKirimSelamatDatang(): void
{
    $pengirim = $this->createMock(PengirimEmail::class);
    $pengirim->expects($this->once())
             ->method('kirim')
             ->with('budi@mail.com', $this->stringContains('Selamat'))
             ->willReturn(true);

    $layanan = new Notifikasi($pengirim);
    $this->assertTrue($layanan->sambut('budi@mail.com'));
}

Ini alasan utama kita memakai interface dan dependency injection di bab OOP: class jadi mudah diuji.

Tes yang baik

  • Cepat dan mandiri (urutan tes tidak boleh saling bergantung).
  • Menguji satu perilaku per tes, dengan nama yang menjelaskannya.
  • Menguji kasus batas: nol, kosong, negatif, nilai maksimum, input salah.
  • Jangan menguji detail internal; uji hasil yang dilihat dari luar.

Error umum

  • No tests found in class → nama method tidak berawalan test atau tidak public.
  • Class "App\Kalkulator" not found → autoload PSR-4 belum diatur di composer.json; jalankan composer dump-autoload.
  • Failed asserting that 2.5 is identical to '2.5' → assertSame memeriksa tipe; samakan tipenya.

Praktikkan langsung, gratis

Tulis dan jalankan kode langsung di browser, dapatkan penilaian otomatis. Daftar gratis kapan saja untuk menyimpan progres dan meraih sertifikat.

Coba latihan sekarang, tanpa daftar
Bagikan: WhatsApp Facebook LinkedIn X