0Pricing
PHP Academy · Pelajaran

Pemalsuan dan Penggantian dengan Mockery

Pisahkan unit dengan pengganti pengujian yang fleksibel.

Pemalsuan dan Penggantian dengan Mockery adalah pelajaran PHP Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar PHP Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus PHP Academy mencakup 4 pelajaran total.

Mengapa Pustaka Tiruan Khusus

PHPUnit menyediakan API objek pengganti pengujiannya sendiri, tetapi Mockery menawarkan sintaks yang lebih lancar dan ekspresif serta kemampuan yang tidak dimiliki tiruan PHPUnit — tiruan parsial, pengintai, pencocokan argumen yang fleksibel, dan ekspektasi berurutan. Untuk kode yang banyak bergantung pada kolaborasi, Mockery sering kali jauh lebih mudah dibaca. Pelajaran ini membahas seluruh jenis objek pengganti dan kapan masing-masing digunakan.

composer require --dev mockery/mockery

Nilai Tetap vs Tiruan vs Pengintai

Kosakata yang tepat mencegah pengujian yang membingungkan:

  • Nilai tetap — mengembalikan nilai yang sudah ditentukan; Anda menegaskan keadaan (hasilnya).
  • Tiruan — memiliki ekspektasi terhadap pemanggilan; Anda menegaskan perilaku (pemanggilan dilakukan dengan benar). Ekspektasi yang gagal membuat pengujian gagal.
  • Pengintai — mencatat pemanggilan dan memungkinkan Anda menegaskannya setelah kejadian.

Aturan praktis: pilih nilai tetap untuk kueri, dan tiruan/pengintai untuk perintah.

Nilai Tetap dengan allows()

Gunakan Mockery::mock() dan allows() (atau shouldReceive()->andReturn()) untuk menyediakan nilai pengembalian yang sudah ditentukan tanpa menegaskan bahwa pemanggilan tersebut terjadi. Di sini, nilai tetap gateway menyediakan nilai tukar yang diketahui agar kita dapat menguji perhitungan secara terpisah.

<?php
use Mockery;
use PHPUnit\Framework\TestCase;

final class ConverterTest extends TestCase
{
    public function test_converts_using_rate(): void
    {
        $rates = Mockery::mock(RateGateway::class);
        $rates->allows()->rateFor('USD', 'EUR')->andReturn(0.9);

        $sut = new Converter($rates);
        self::assertSame(90.0, $sut->convert(100.0, 'USD', 'EUR'));

        Mockery::close();
    }
}

Tiruan dengan expects()

Ketika interaksi itu sendiri merupakan kontrak — misalnya, "sebuah surel harus dikirim tepat satu kali" — gunakan expects() atau shouldReceive()->once(). Mockery memverifikasi ekspektasi selama Mockery::close(); pemanggilan yang tidak terpenuhi membuat pengujian gagal.

<?php
use Mockery;

$mailer = Mockery::mock(Mailer::class);
$mailer->expects()
       ->send(Mockery::type(Message::class))
       ->once();

$service = new SignupService($mailer);
$service->register('ada@example.com');

Mockery::close(); // fails here if send() was never called

Pencocok Argumen

Pencocok milik Mockery memungkinkan ekspektasi dibuat selonggar atau seketat yang diperlukan:

  • Mockery::any() — nilai apa pun.
  • Mockery::type('string') / nama kelas — pemeriksaan tipe.
  • Mockery::on(fn($a) => ...) — predikat khusus.
  • Mockery::capture($var) — menangkap argumen untuk penegasan selanjutnya.
<?php
use Mockery;

$repo = Mockery::mock(UserRepo::class);
$repo->expects()
     ->save(Mockery::on(fn(User $u) => $u->isActive()))
     ->once()
     ->andReturnTrue();

Urutan Pengembalian dan Pengembalian Dinamis

Anda dapat mengatur beberapa nilai pengembalian untuk berbagai pemanggilan, atau menghitung pengembalian dari argumen dengan andReturnUsing(). Ini memodelkan logika percobaan ulang, paginasi, atau kolaborator yang memiliki keadaan.

<?php
use Mockery;

$api = Mockery::mock(HttpClient::class);
// First call throws, second succeeds (retry test):
$api->shouldReceive('get')
    ->twice()
    ->andThrow(new \RuntimeException('timeout'))
    ->andReturn('{"ok":true}');

// Or derive the return from the input:
$api->shouldReceive('echo')
    ->andReturnUsing(fn(string $in) => strtoupper($in));

Pengintai: Menegaskan Setelah Kejadian

Pengintai membalik urutannya: bertindak terlebih dahulu, lalu menegaskan. Mockery::spy() mencatat pemanggilan; setelahnya Anda menanyakannya dengan shouldHaveReceived(). Pengintai menjaga struktur Atur-Bertindak-Tegaskan tetap bersih ketika Anda tidak ingin ekspektasi yang telah ditetapkan sebelumnya memenuhi bagian penyiapan.

<?php
use Mockery;

$logger = Mockery::spy(Logger::class);

$service = new PaymentService($logger);
$service->charge(500);

// Assertions happen AFTER the action:
$logger->shouldHaveReceived('info')
       ->with(Mockery::pattern('/charged 500/'))
       ->once();

Mockery::close();

Tiruan Parsial

Terkadang Anda menginginkan objek nyata, tetapi dengan satu metode yang ditimpa — sebuah tiruan parsial. makePartial() milik Mockery meneruskan pemanggilan ke metode nyata, kecuali metode yang Anda beri ekspektasi. Gunakan secukupnya: ketergantungan berat pada tiruan parsial biasanya menandakan bahwa sebuah kelas melakukan terlalu banyak hal.

<?php
use Mockery;

$report = Mockery::mock(Report::class)->makePartial();
// Only stub the slow/external method; the rest runs for real
$report->shouldReceive('fetchRawData')->andReturn(['a', 'b', 'c']);

// real summarize() runs, using the stubbed data
$summary = $report->summarize();

Jangan Menirukan yang Bukan Milik Anda

Prinsip inti pengujian: hindari menirukan kelas pihak ketiga secara langsung. API mereka dapat berubah dan tiruan Anda dapat diam-diam menyimpang dari kenyataan. Sebagai gantinya, bungkus mereka di balik antarmuka Anda sendiri dan tirukan antarmuka tersebut. Tiruan itu kemudian memverifikasi kontrak Anda, sementara pengujian integrasi adaptor memverifikasi pengikatan yang sebenarnya.

<?php
interface PaymentGateway {            // you own this
    public function charge(int $cents, string $token): string;
}

final class StripeGateway implements PaymentGateway {
    public function __construct(private \Stripe\StripeClient $client) {}
    public function charge(int $cents, string $token): string {
        return $this->client->paymentIntents->create([/* ... */])->id;
    }
}
// Tests mock PaymentGateway, never \Stripe\StripeClient directly.

Selalu Tutup dan Verifikasi Jumlah Pemanggilan

Dua hal operasional yang wajib dilakukan:

  • Panggil Mockery::close() di dalam tearDown() (atau gunakan sifat MockeryPHPUnitIntegration) agar ekspektasi benar-benar diverifikasi dan variabel global dibersihkan.
  • Gunakan jumlah yang eksplisit (once(), times(n), never()) — tiruan yang tidak jelas memungkinkan bug lolos.
<?php
use PHPUnit\Framework\TestCase;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;

final class OrderServiceTest extends TestCase
{
    use MockeryPHPUnitIntegration; // auto-calls Mockery::close()

    public function test_does_not_refund_paid_orders(): void
    {
        $gw = \Mockery::mock(PaymentGateway::class);
        $gw->shouldReceive('refund')->never();
        // ... exercise SUT ...
    }
}

Ekspektasi Berurutan

Terkadang urutan pemanggilan merupakan bagian dari kontrak — Anda harus memanggil beginTransaction() sebelum commit(). ordered() milik Mockery memberlakukan urutan, sehingga pengujian gagal jika pemanggilan tiba dalam urutan yang salah. Gunakan hanya ketika urutan benar-benar penting; menentukan urutan secara berlebihan membuat pengujian rapuh.

<?php
use Mockery;

$tx = Mockery::mock(Transaction::class);
$tx->shouldReceive('begin')->once()->ordered();
$tx->shouldReceive('commit')->once()->ordered();

$service = new TransferService($tx);
$service->run();

Mockery::close(); // fails if commit() happened before begin()

Pemeriksaan Singkat

Nilai tetap atau tiruan — mana digunakan untuk apa?

Ringkasan

Anda telah menguasai objek pengganti Mockery:

  • Nilai tetap (allows) untuk kueri; tiruan (expects) untuk perintah; pengintai untuk penegasan setelah kejadian.
  • Pencocok argumen (type, on, capture) menyesuaikan tingkat keketatan.
  • Urutan pengembalian dan andReturnUsing memodelkan kolaborator yang memiliki keadaan atau bersifat dinamis.
  • Tiruan parsial menimpa satu metode; gunakan secukupnya.
  • Jangan menirukan sesuatu yang bukan milik Anda — bungkus pihak ketiga di balik antarmuka Anda.
  • Selalu gunakan Mockery::close() dan tegaskan jumlah pemanggilan secara eksplisit.

Berikutnya: pengujian integrasi dan fungsional.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Pemalsuan dan Penggantian dengan Mockery” gratis?

Ya — teks lengkap “Pemalsuan dan Penggantian dengan Mockery” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus PHP Academy, upgrade ke CoddyKit PRO. Kursus PHP Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Pemalsuan dan Penggantian dengan Mockery”?

Pisahkan unit dengan pengganti pengujian yang fleksibel. Kamu berlatih PHP Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai PHP Academy?

Tidak diperlukan pengalaman sebelumnya. PHP Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.

Berapa lama pelajaran “Pemalsuan dan Penggantian dengan Mockery” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran PHP Academy ini?

Ya. Setiap pelajaran PHP Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Alur Kerja Pengembangan Berbasis Pengujian
  2. Pemalsuan dan Penggantian dengan Mockery
  3. Pengujian Integrasi dan Fungsional
  4. Pengujian Mutasi dengan Infection
← Kembali ke PHP Academy