Paket ini membantu meniru fungsi php internal sesederhana mungkin. Gunakan paket ini ketika Anda membutuhkan fungsi tiruan seperti: time()
, str_contains()
, rand
, dll.
Instalasi
Penggunaan
Waktu proses mengolok-olok
Tiruan yang telah ditentukan sebelumnya
Campuran dari dua cara sebelumnya
PHPUnit 9
PHPUnit 10 dan lebih tinggi
Daftarkan Ekstensi PHPUnit
Daftarkan tiruan
Negara
Melacak panggilan
Fungsi dengan namespace global
Implementasi fungsi internal
Fungsi dalaman
Pembatasan
Penyedia Data
komposer memerlukan xepozz/internal-mocker --dev
Ide utamanya cukup sederhana: daftarkan Listener untuk PHPUnit dan panggil ekstensi Mocker terlebih dahulu.
Buat file baru tests/MockerExtension.php
Rekatkan kode berikut ke dalam file yang dibuat:
<?phpdeclare(strict_types=1);namespace AppTests;gunakan PHPUnitRunnerBeforeTestHook;gunakan PHPUnitRunnerBeforeFirstTestHook;gunakan XepozzInternalMockerMocker;gunakan XepozzInternalMockerMockerState;kelas akhir MockerExtension mengimplementasikan BeforeTestHook, BeforeFirstTestHook {fungsi publik mengeksekusiBeforeFirstTest(): void{$mocks = [];$mocker = new Mocker();$mocker->load($mocks); MockerState::saveState(); }fungsi publik mengeksekusiBeforeTest(string $test): void{ MockerState::resetState(); } }
Daftarkan hook sebagai ekstensi di phpunit.xml.dist
<ekstensi> <kelas ekstensi="AppTestsMockerExtension"/> </ekstensi>
Buat file baru tests/MockerExtension.php
Rekatkan kode berikut ke dalam file yang dibuat:
<?phpdeclare(strict_types=1);namespace AppTests;gunakan PHPUnitEventTestPreparationStarted;gunakan PHPUnitEventTestPreparationStartedSubscriber;gunakan PHPUnitEventTestSuiteStarted;gunakan PHPUnitEventTestSuiteStartedSubscriber;gunakan PHPUnitRunnerExtensionExtension;gunakan PHPUnitRunnerExtensionFacade;gunakan PHPUnitRunnerExtensionParameterCollection; gunakan PHPUnitTextUIConfigurationConfiguration; gunakan XepozzInternalMockerMocker; gunakan XepozzInternalMockerMockerState; kelas akhir MockerExtension mengimplementasikan Ekstensi {bootstrap fungsi publik(Konfigurasi $konfigurasi, Fasad $fasad, ParameterCollection $parameter): void{$facade->registerSubscribers(kelas baru () mengimplementasikan StartedSubscriber {pemberitahuan fungsi publik(Dimulai $event): void{ Ekstensi Mocker::load(); } }, kelas baru mengimplementasikan PreparationStartedSubscriber {public function notify(PreparationStarted $event): void{ MockerState::resetState(); } }, ); }fungsi statis publik load(): void{$mocks = [];$mocker = new Mocker();$mocker->load($mocks); MockerState::saveState(); } }
Daftarkan hook sebagai ekstensi di phpunit.xml.dist
<ekstensi> <bootstrap class="AppTestsMockerExtension"/> </ekstensi>
Di sini Anda telah mendaftarkan ekstensi yang akan dipanggil setiap kali Anda menjalankan ./vendor/bin/phpunit
.
Secara default, semua fungsi akan dibuat dan disimpan ke file /vendor/bin/xepozz/internal-mocker/data/mocks.php
.
Ganti argumen pertama konstruktor Mocker
untuk mengubah jalur:
$mocker = new Mocker('/path/to/your/mocks.php');
Paket ini mendukung beberapa cara untuk meniru fungsi:
Waktu proses mengolok-olok
Ejekan yang telah ditentukan sebelumnya
Campuran dari dua cara sebelumnya
Jika Anda ingin membuat test case Anda digunakan dengan fungsi tiruan, Anda harus mendaftarkannya sebelumnya.
Kembali ke MockerExtension::executeBeforeFirstTest
yang dibuat dan edit variabel $mocks
.
$mengolok-olok = [ ['namespace' => 'AppService','name' => 'waktu', ], ];
Tiruan ini akan memproksi setiap panggilan time()
di bawah namespace AppService
melalui pembungkus yang dihasilkan.
Saat Anda ingin meniru hasil pengujian, Anda harus menulis kode berikut ke dalam kasus pengujian yang diperlukan:
MockerState::addCondition( 'AppService', // namespace 'waktu', // nama fungsi [], // argumen 100 // hasil);
Anda juga dapat menggunakan panggilan balik untuk mengatur hasil fungsi:
MockerState::addCondition( '', // namespace 'headers_sent', // nama fungsi [null, null], // kedua argumen adalah referensi dan belum diinisialisasi pada pemanggilan fungsi fn (&$file, &$line) => $file = $line = 123, // hasil panggilan balik);
Jadi test case Anda akan terlihat seperti berikut:
<?phpnamespace AppTests;gunakan AppService;gunakan PHPUnitFrameworkTestCase;kelas ServiceTest memperluas TestCase {fungsi publik testRun2(): void{$service = Layanan baru(); MockerState::addCondition('AppService','waktu', [],100);$ini->assertEquals(100, $layanan->doSomething()); } }
Lihat contoh lengkap di XepozzInternalMockerTestsIntegrationDateTimeTest::testRun2
Tiruan yang telah ditentukan sebelumnya memungkinkan Anda meniru perilaku secara global.
Artinya Anda tidak perlu menulis MockerState::addCondition(...)
ke dalam setiap kasus pengujian jika Anda ingin menirunya untuk keseluruhan proyek.
Ingatlah bahwa fungsi yang sama dari namespace yang berbeda tidaklah sama untuk
Mocker
.
Jadi kembali ke MockerExtension::executeBeforeFirstTest
yang dibuat dan edit variabel $mocks
.
$mengolok-olok = [ ['namespace' => 'AppService','name' => 'time','result' => 150,'arguments' => [], ], ];
Setelah varian ini, setiap AppServicetime()
akan mengembalikan 150
.
Anda dapat menambahkan banyak tiruan. Mocker
membandingkan nilai arguments
dengan argumen pemanggilan fungsi dan mengembalikan hasil yang diperlukan.
Campuran berarti Anda dapat menggunakan tiruan yang telah ditentukan sebelumnya dan tiruan Runtime setelahnya.
Jika Anda menggunakan Runtime mock
Anda mungkin menghadapi masalah bahwa setelah fungsi tiruan Anda masih mengejeknya di kasus pengujian lainnya.
MockerState::saveState()
dan MockerState::resetState()
memecahkan masalah ini.
Metode ini menyimpan status "saat ini" dan membongkar setiap Runtime mock
yang diterapkan.
Menggunakan MockerState::saveState()
setelah Mocker->load($mocks)
hanya menyimpan tiruan yang telah ditentukan sebelumnya .
Anda dapat melacak panggilan fungsi tiruan dengan menggunakan metode MockerState::getTraces()
.
$jejak = MockerState::getTraces('AppService', 'waktu');
$traces
akan berisi array dengan struktur berikut:
[ ['argumen' => [], // argumen fungsi'jejak' => [], // hasil debug_backtrace fungsi'hasil' => 1708764835, // hasil fungsi],// ... ]
Semua fungsi internal dihentikan agar kompatibel dengan yang asli. Itu membuat fungsi menggunakan argumen yang direferensikan ( &$file
) seperti aslinya.
Mereka terletak di file src/stubs.php
.
Jika Anda perlu menambahkan tanda tangan fungsi baru, ganti argumen kedua dari konstruktor Mocker
:
$mocker = Mocker baru(stubPath: '/path/to/your/stubs.php');
Cara Anda meniru fungsi global adalah dengan menonaktifkannya di php.ini
: https://www.php.net/manual/en/ini.core.php#ini.disable-functions
Cara terbaik adalah menonaktifkannya hanya untuk pengujian dengan menjalankan perintah dengan tanda tambahan:
php -ddisable_functions=${functions} ./vendor/bin/phpunit
Jika Anda menggunakan PHPStorm, Anda dapat mengatur perintah di bagian
Run/Debug Configurations
. Tambahkan tanda-ddisable_functions=${functions}
ke bidangInterpreter options
.
Anda dapat menyimpan perintah di file
composer.json
di bawah bagianscripts
.
{ "scripts": {"test": "php -ddisable_functions=waktu, serialisasi, header, tanggal ./vendor/bin/phpunit" } }
Ganti
${functions}
dengan daftar fungsi yang ingin Anda tiru, pisahkan dengan koma, misalnya:time,rand
.
Jadi sekarang Anda juga bisa meniru fungsi global.
Saat Anda menonaktifkan suatu fungsi di php.ini
Anda tidak dapat memanggilnya lagi. Artinya, Anda harus menerapkannya sendiri.
Jelasnya, hampir semua fungsi yang diimplementasikan di PHP terlihat sama dengan fungsi Bash.
Cara terpendek untuk mengimplementasikan suatu fungsi adalah dengan menggunakan sintaks `bash command`
:
$mengolok-olok[] = [ 'namespace' => '', 'nama' => 'waktu', 'fungsi' => fn () => `tanggal +%s`, ];
Ingatlah bahwa membiarkan fungsi global tanpa implementasi akan menyebabkan pemanggilan fungsi tersebut, yang akan menyebabkan kesalahan fatal.
Terkadang Anda mungkin menghadapi situasi yang tidak menyenangkan ketika fungsi yang diolok-olok tidak diolok-olok tanpa paksaan menggunakan namespace
function
. Ini mungkin berarti Anda mencoba membuat file juru bahasa PHP di @dataProvider
. Berhati-hatilah dan sebagai solusinya saya mungkin menyarankan Anda untuk memanggil pengejek di konstruktor pengujian. Jadi pertama-tama pindahkan semua kode dari metode ekstensi Anda executeBeforeFirstTest
ke metode statis baru dan panggil kode tersebut dalam metode executeBeforeFirstTest
dan __construct
.
kelas terakhir MyTest memperluas PHPUnitFrameworkTestCase {fungsi publik __construct(?string $name = null, array $data = [], $dataName = '') {AppTestsMockerExtension::load();parent::__construct($name, $data, $dataName); } /// ...}
kelas terakhir MockerExtension mengimplementasikan BeforeTestHook, BeforeFirstTestHook {fungsi publik mengeksekusiBeforeFirstTest(): void{self::load(); }fungsi statis publik load(): void{$mocks = [];$mocker = new Mocker();$mocker->load($mocks); MockerState::saveState(); }fungsi publik mengeksekusiBeforeTest(string $test): void{ MockerState::resetState(); } }
Itu semua karena PHPUnit 9.5 dan sistem manajemen acara yang lebih rendah. Fungsionalitas Penyedia Data mulai berfungsi sebelum peristiwa apa pun, sehingga tidak mungkin untuk meniru fungsi tersebut di awal waktu proses.