Apakah ada cara untuk mendefinisikan ekspektasi palsu yang berbeda untuk argumen input yang berbeda? Misalnya, saya memiliki kelas lapisan database yang disebut DB. Kelas ini memiliki metode yang disebut "Query (string $ query)", metode tersebut mengambil string kueri SQL pada input. Dapatkah saya membuat tiruan untuk kelas (DB) ini dan menetapkan nilai kembalian yang berbeda untuk panggilan metode Kueri yang berbeda yang bergantung pada string kueri masukan?
117
Jawaban:
Library PHPUnit Mocking (secara default) menentukan apakah ekspektasi cocok hanya berdasarkan matcher yang diteruskan ke
expects
parameter dan batasan yang diteruskan kemethod
. Karena itu, duaexpect
panggilan yang hanya berbeda dalam argumen yang diteruskanwith
akan gagal karena keduanya akan cocok tetapi hanya satu yang akan memverifikasi sebagai memiliki perilaku yang diharapkan. Lihat kotak reproduksi setelah contoh kerja sebenarnya.Untuk masalah Anda, Anda perlu menggunakan
->at()
atau->will($this->returnCallback(
seperti yang dijelaskan dalamanother question on the subject
.Contoh:
Mereproduksi:
Reproduksi mengapa dua -> dengan () panggilan tidak berfungsi:
Hasil dalam
sumber
$this->anything()
sebagai salah satu parameter untuk->logicalOr()
memungkinkan Anda memberikan nilai default untuk argumen lain selain yang Anda minati.Ini tidak ideal untuk digunakan
at()
jika Anda dapat menghindarinya karena seperti yang diklaim oleh dokumen merekaSejak 4.1 Anda dapat menggunakan
withConsecutive
mis.Jika Anda ingin membuatnya kembali pada panggilan berturut-turut:
sumber
Fatal error: Call to undefined method PHPUnit_Framework_MockObject_Builder_InvocationMocker::withConsecutive()
, ditingkatkan ke 4.1 dalam sekejap dengan Komposer dan itu berfungsi.willReturnOnConsecutiveCalls
membunuhnya.Dari apa yang saya temukan, cara terbaik untuk mengatasi masalah ini adalah dengan menggunakan fungsionalitas peta nilai PHPUnit.
Contoh dari dokumentasi PHPUnit :
Tes ini berhasil. Seperti yang Anda lihat:
Dari apa yang saya ketahui, fitur ini telah diperkenalkan di PHPUnit 3.6 , jadi fitur ini cukup "tua" sehingga dapat digunakan dengan aman di hampir semua lingkungan pengembangan atau pementasan dan dengan alat integrasi berkelanjutan apa pun.
sumber
Tampaknya Mockery ( https://github.com/padraic/mockery ) mendukung ini. Dalam kasus saya, saya ingin memeriksa bahwa 2 indeks dibuat pada database:
Ejekan, karya:
PHPUnit, ini gagal:
Mockery juga memiliki sintaks IMHO yang lebih bagus. Tampaknya sedikit lebih lambat dari kemampuan tiruan bawaan PHPUnits, tetapi YMMV.
sumber
Intro
Oke saya melihat ada satu solusi yang disediakan untuk Mockery, jadi karena saya tidak suka Mockery, saya akan memberi Anda alternatif Nubuat tetapi saya sarankan Anda terlebih dahulu membaca tentang perbedaan antara Mockery dan Prophecy terlebih dahulu.
Singkat cerita : "Nubuatan menggunakan pendekatan yang disebut pengikatan pesan - itu berarti bahwa perilaku metode tidak berubah seiring waktu, tetapi diubah oleh metode lain."
Kode bermasalah dunia nyata untuk dibahas
Solusi PhpUnit Prophecy
Ringkasan
Sekali lagi, Nubuat lebih dahsyat! Trik saya adalah memanfaatkan sifat pengikatan pesan dari Prophecy dan meskipun sayangnya itu terlihat seperti kode neraka javascript panggilan balik yang khas, dimulai dengan $ self = $ this; karena Anda sangat jarang harus menulis unit test seperti ini, saya pikir ini adalah solusi yang bagus dan pasti mudah diikuti, debug, karena ini benar-benar menggambarkan eksekusi program.
BTW: Ada alternatif kedua tetapi perlu mengubah kode yang kami uji. Kita bisa membungkus pembuat onar dan memindahkan mereka ke kelas terpisah:
bisa dibungkus sebagai:
dan hanya itu, tetapi karena saya tidak ingin membuat kelas lain untuk itu, saya lebih suka yang pertama.
sumber