Olok-olok bertujuan untuk menguji tingkah laku objek sebenar.
Ia mensimulasikan kebergantungan, jadi anda tidak perlu memanggil sumber luaran yang boleh melambatkan ujian unit dengan ketara.
Anda boleh menentukan jangkaan dan mengesahkannya.
Sebagai contoh, anda boleh memastikan bahawa kaedah dipanggil bilangan kali tertentu dan/atau dengan parameter tertentu:
use PHPUnit\Framework\TestCase; class MyTest extends TestCase { public function testMockExample(): void { $depencencyMock = $this->createMock(MyDependency::class); $dependencyMock->expects($this->exactly(2)) ->method('someMethod') ->with('some parameter'); $classToTest = new ClassToTest($dependencyMock); } }
willReturn() memastikan keserasian dengan jenis pulangan:
// In code class MyClass { public function getNum(): int { } } // In tests $myClassMock = $this->createMock(MyClass::class); $myClassMock->expects($this->once()) ->method('getNum') ->willReturn(2);
Anda juga boleh menggunakan willReturnCallback jika anda ingin menguji tingkah laku dinamik berdasarkan parameter input.
Memandangkan ejekan hanya meniru tingkah laku sebenar, mudah untuk terlepas maksud. Jom bincang amalan buruk biasa:
❌ Jangan buat begitu:
$colorServiceMock = $this->createMock(ColorService::class); $colorServiceMock->method('hexToName') ->willReturn('red'); $color = (new MyClass($colorServiceMock))->getColorName('ff0000');
✅ Sebaliknya, tambahkan beberapa jangkaan:
$colorServiceMock->expects($this->once()) ->method('hexToName') ->with('00f00') ->willReturn('green'); $color = (new MyClass($colorServiceMock))->getColorName('00f00');
Ingat ejekan bertujuan untuk mengesahkan interaksi.
Mari kita uji MyClass yang melaksanakan SomeInterface.
❌ Jangan buat begitu:
$myclassMock = $this->createMock(MyClass::class);
✅ Sebaliknya, ejek antara muka:
$myclassMock = $this->createMock(SomeInterface::class);
Ejekan memberi tumpuan kepada tingkah laku. Antara muka biasanya tidak berubah, kerana anda sepatutnya mengubah suai pelaksanaan, bukan kontrak.
Tomas Votruba menerangkan masalah ini dengan indah: 5 Cara untuk Mengeluarkan Nilai daripada Ujian Terlalu Banyak
Mudah untuk mengabaikan gandingan yang ketat antara komponen:
$productRepositoryMock = $this->createMock(ProductRepository::class); $invoiceRepositoryMock = $this->createMock(InvoiceRepository::class); $emailServiceMock = $this->createMock(EmailService::class); $overComplexService = new OverComplexService($productRepositoryMock, $invoiceRepositoryMock, $emailServiceMock);
Contoh di atas memecahkan pemisahan kebimbangan, dan ejekan mengekalkan amalan buruk itu.
Mocks ialah alat yang berkuasa, tetapi ujian unit tidak mencukupi. Anda memerlukan pelbagai jenis ujian lain (cth, penyepaduan, e2e).
Selain amalan buruk, terdapat tanda-tanda lain yang boleh menunjukkan bahawa ejekan disalahgunakan atau digunakan secara berlebihan dalam projek:
Martin Fowler menulis siaran hebat yang menerangkan sebab Mocks Aren't Stubs.
Mari lihat situasi konkrit di mana anda mungkin menggunakannya:
Berikut ialah beberapa kes ujian di mana ejekan lebih masuk akal:
Anda boleh membuat stub dengan PHPUnit dengan mudah:
use PHPUnit\Framework\TestCase; class MyTest extends TestCase { public function testMockExample(): void { $depencencyMock = $this->createMock(MyDependency::class); $dependencyMock->expects($this->exactly(2)) ->method('someMethod') ->with('some parameter'); $classToTest = new ClassToTest($dependencyMock); } }
Berikut ialah beberapa kes ujian yang mana stub lebih masuk akal:
Ringkasnya, stub bukan bertujuan untuk memeriksa kelakuan objek sebenar tetapi menyatakan.
Tujuan utama ujian unit adalah untuk memastikan setiap unit/komponen berfungsi seperti yang diharapkan, tetapi anda perlu mengekalkan ujian tersebut sebagai tambahan kepada kod sebenar.
Stub boleh memudahkan persediaan ujian dan sangat cekap untuk senario mudah yang anda tidak perlu menjejaki panggilan kaedah dan interaksi.
Ia boleh menghalang kerumitan yang tidak perlu dengan memastikan beberapa ujian anda fokus.
Mocks boleh menjejaki panggilan kaedah dan parameternya.
Jangan lupa untuk mengembalikan nilai yang mewakili tingkah laku sebenar. Jika tidak, anda mungkin mengalami rasa selamat yang palsu.
Mock harus digunakan dengan berhati-hati untuk mengelakkan kerumitan yang tidak perlu untuk penyelenggaraan.
Atas ialah kandungan terperinci PHP: Patutkah saya mengejek atau perlu pergi?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!