Testing dengan Pest — Testing

Apa itu Pest? Pest adalah framework testing PHP yang dibangun di atas PHPUnit dengan sintaks yang lebih bersih dan ekspresif. Pest tidak menggantikan PHPUnit…

Pest adalah framework testing PHP yang dibangun di atas PHPUnit. Bedanya di cara menulis: tanpa class dan method, cukup fungsi it() atau test() yang dibaca seperti kalimat, dan expect() yang pemeriksanya dirangkai. Yang menjalankan test-nya tetap PHPUnit di belakang layar. Bayangin dua resep untuk masakan yang sama: satu ditulis sebagai formulir berkolom-kolom, satu lagi sebagai kalimat biasa, "pastikan nasinya pulen". Masakannya sama, cuma cara menulisnya yang beda. Formulirnya PHPUnit, kalimatnya Pest.

🧪 Tebakan cepat: expect(add(1, 2))->toBe('3'). Lulus atau gagal? Tebak dulu, jawabannya ada di bagian "expect() dan pemeriksanya".

Test pertama dengan Pest

Satu file tests/Unit/MathTest.php. Supaya ringkas, fungsi yang dites ditaruh di atasnya (di project sungguhan dia tinggal di folder app):

<?php

function add($a, $b)
{
    return $a + $b;
}

function double($n)
{
    return $n * 2;
}

it('can add numbers', function () {
    expect(add(1, 2))->toBe(3);
});

Menjalankan: ./vendor/bin/pest

   PASS  Tests\Unit\MathTest
  ✓ it can add numbers

  Tests:    1 passed (1 assertions)
  Duration: 0.05s

Satu baris per test: ✓ lulus, ⨯ gagal. Di Laravel, php artisan test mencetak format yang sama. Kalau ada yang gagal, di bawah daftarnya muncul blok FAILED berisi nama test, pesannya, dan potongan kode dengan panah ➜ di baris yang gagal.

expect() dan pemeriksanya

Ini jawaban tebakannya: expect(add(1, 2))->toBe('3') gagal. toBe membandingkan dengan ===, jadi int 3 dan teks '3' beda:

   FAIL  Tests\Unit\MathTest
  ⨯ it can add numbers
  ────────────────────────────────────────────────────────────────────────────
   FAILED  Tests\Unit\MathTest > it can add numbers
  Failed asserting that 3 is identical to '3'.

  at tests/Unit/MathTest.php:14
     10▕     return $n * 2;
     11▕ }
     12▕
     13▕ it('can add numbers', function () {
  ➜  14▕     expect(add(1, 2))->toBe('3');
     15▕ });

  1   tests/Unit/MathTest.php:14


  Tests:    1 failed (1 assertions)
  Duration: 0.06s

toEqual('3') lulus, karena dia membandingkan longgar (==). Pemeriksa yang paling sering dipakai:

Pemeriksa Lulus kalau
toBe(3) sama persis, tipe ikut dicek (===)
toEqual('3') sama setelah dibandingkan longgar (==)
toBeTrue() / toBeFalse() persis true / false
toBeGreaterThan(5) lebih besar dari 5
toContain('a') array (atau teks) memuat 'a'
toBeEmpty() kosong, misalnya [] atau ''
toHaveCount(3) isinya ada 3

Pemeriksa bisa dirangkai, dan not membalik pemeriksa sesudahnya:

expect($nama)->toBeString()->not->toBeEmpty();

expect($user)->toBeObject()
    ->and($user->name)->toBe('Budi');

Dataset: satu test, banyak data

it('doubles a number', function (int $input, int $expected) {
    expect(double($input))->toBe($expected);
})->with([
    [1, 2],
    [5, 10],
    [0, 0],
]);

Kenapa barisnya perlu lebih dari satu? Bayangin double keliru ditulis return $n + 2;. Dengan satu baris [2, 4] test-nya tetap lulus, karena kebetulan 2 + 2 = 2 × 2. Baris [1, 2] dan [5, 10] langsung menangkapnya.

describe(): mengelompokkan test

describe('Kalkulator', function () {
    it('menambahkan dua angka', function () {
        expect(add(2, 3))->toBe(5);
    });
});

Nama kelompoknya ikut dicetak di depan: `Kalkulator` → it menambahkan dua angka.

Dari PHPUnit ke Pest

// PHPUnit
class MathTest extends TestCase
{
    public function test_add(): void
    {
        $this->assertSame(3, add(1, 2));
    }
}

// Pest
it('adds', function () {
    expect(add(1, 2))->toBe(3);
});

Pest berjalan di atas PHPUnit, jadi file PHPUnit dan file Pest bisa hidup berdampingan di satu project, dan pindahnya boleh pelan-pelan. Di dalam test Pest, $this->assertSame(...) juga tetap bisa dipakai.

Di latihan: tiru expect() sendiri

Sandbox latihan menjalankan PHP biasa tanpa Pest. Jadi kamu membuat expect() sendiri: fungsi yang mengembalikan array berisi fungsi pemeriksa, dan tiap pemeriksa sudah "memegang" nilainya lewat use ($value):

function expect($value): array
{
    return [
        'toBe' => function ($expected) use ($value) {
            return $value === $expected;
        },
    ];
}

echo "toBe: " . (expect(5)['toBe'](5) ? 'PASS' : 'FAIL') . "\n";   // toBe: PASS

⚠️ Jebakan yang sering ketemu

TL;DR: Pest menulis test sebagai it('deskripsi', function () { ... }) atau test(...), tanpa class, lalu memeriksa dengan expect($nilai)->toBe($harapan). toBe membandingkan ketat (===), toEqual longgar (==). Pemeriksa bisa dirangkai, not membaliknya, ->and($lain) pindah ke nilai lain. ->with([[1, 2], [5, 10]]) menjalankan satu test untuk tiap baris data, dan tiap baris dicetak sebagai test sendiri, misalnya it doubles a number with (1, 2). Pest dibangun di atas PHPUnit dan dijalankan dengan ./vendor/bin/pest. Di sandbox latihan, expect() ditiru dengan array fungsi yang memakai use ($value).

Yang akan kamu pelajari