Saya sedang membangun perpustakaan kelas yang akan memiliki beberapa metode publik & pribadi. Saya ingin dapat menguji unit metode pribadi (kebanyakan sambil mengembangkan, tetapi juga bisa berguna untuk refactoring di masa depan).
Apa cara yang benar untuk melakukan ini?
.net
unit-testing
tdd
private
Eric Labashosky
sumber
sumber
pre-historic
dalam hal tahun Internet, tetapi pengujian unit metode pribadi sekarang mudah dan lurus ke depan, dengan Visual Studio menghasilkan kelas accessor yang diperlukan ketika diperlukan dan pra-mengisi logika tes dengan potongan yang hampir sesuai dengan keinginan seseorang untuk tes fungsional sederhana. Lihat misalnya. msdn.microsoft.com/en-us/library/ms184807%28VS.90%29.aspxJawaban:
Jika Anda menggunakan .net, Anda harus menggunakan InternalsVisibleToAttribute .
sumber
#if DEBUG
sekitarInternalsVisibleTo
atribut untuk membuatnya tidak berlaku untuk kode rilis?#if RELEASE_TEST
sekitarInternalsVisibleTo
seperti yang disarankan Mike, dan buat salinan konfigurasi build rilis Anda yang menentukanRELEASE_TEST
. Anda bisa menguji kode rilis Anda dengan optimisasi, tetapi ketika Anda benar-benar membangun untuk rilis, tes Anda akan dihilangkan.Jika Anda ingin menguji unit metode pribadi, sesuatu mungkin salah. Tes unit (umumnya berbicara) dimaksudkan untuk menguji antarmuka kelas, yang berarti metode publik (dan dilindungi). Anda tentu saja dapat "meretas" solusi untuk ini (bahkan jika hanya dengan membuat metode publik), tetapi Anda mungkin juga ingin mempertimbangkan:
sumber
Mungkin tidak berguna untuk menguji metode pribadi. Namun, saya kadang-kadang juga suka memanggil metode pribadi dari metode pengujian. Sebagian besar waktu untuk mencegah duplikasi kode untuk pembuatan data uji ...
Microsoft menyediakan dua mekanisme untuk ini:
Pengakses
Namun, mekanisme ini kadang-kadang agak sulit dilakukan ketika datang ke perubahan antarmuka kelas asli. Jadi, sebagian besar kali saya menghindari menggunakan ini.
Kelas PrivateObject Cara lain adalah menggunakan Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject
sumber
Saya tidak setuju dengan filosofi "Anda hanya tertarik untuk menguji antarmuka eksternal". Ini seperti mengatakan bahwa bengkel mobil seharusnya hanya melakukan tes untuk melihat apakah roda berputar. Ya, pada akhirnya saya tertarik pada perilaku eksternal tetapi saya suka tes internal saya sendiri, pribadi untuk menjadi sedikit lebih spesifik dan to the point. Ya, jika saya refactor, saya mungkin harus mengubah beberapa tes, tetapi kecuali itu adalah refactor besar, saya hanya perlu mengubah beberapa dan fakta bahwa tes internal lainnya (tidak berubah) masih berfungsi adalah indikator yang bagus bahwa refactoring telah berhasil.
Anda dapat mencoba untuk menutupi semua kasus internal hanya menggunakan antarmuka publik dan secara teoritis dimungkinkan untuk menguji setiap metode internal (atau setidaknya setiap yang penting) sepenuhnya dengan menggunakan antarmuka publik tetapi Anda mungkin harus berdiri di atas kepala untuk mencapai ini dan koneksi antara kasus uji yang dijalankan melalui antarmuka publik dan bagian internal dari solusi yang dirancang untuk diuji mungkin sulit atau tidak mungkin untuk dilihat. Setelah ditunjukkan, pengujian individual yang menjamin bahwa mesin internal berfungsi dengan baik layak dilakukan terhadap perubahan tes kecil yang terjadi dengan refactoring - setidaknya itulah pengalaman saya. Jika Anda harus membuat perubahan besar pada pengujian Anda untuk setiap refactoring, maka mungkin ini tidak masuk akal, tetapi dalam hal ini, mungkin Anda harus memikirkan kembali desain Anda sepenuhnya.
sumber
FooService
yang harus dilakukanX
, yang harus Anda pedulikan adalah bahwa hal itu memang dilakukanX
ketika diminta. Bagaimana itu seharusnya tidak masalah. Jika ada masalah di kelas yang tidak dapat dilihat melalui antarmuka (tidak mungkin), itu masih validFooService
. Jika itu masalah yang sangat terlihat melalui antarmuka, tes pada anggota masyarakat harus mendeteksi itu. Intinya adalah bahwa selama roda berputar dengan benar, dapat digunakan sebagai roda.PrivMethod
, tes diPubMethod
mana panggilanPrivMethod
harus memaparkannya? Apa yang terjadi ketika Anda mengubahSimpleSmtpService
keGmailService
? Tiba-tiba tes pribadi Anda menunjukkan kode yang tidak lagi ada atau mungkin bekerja secara berbeda dan akan gagal, meskipun aplikasi dapat bekerja dengan sempurna seperti yang dirancang. Jika ada pemrosesan kompleks yang akan berlaku untuk kedua pengirim email, mungkin harus dalamEmailProcessor
yang dapat digunakan oleh keduanya dan diuji secara terpisah?Dalam kasus yang jarang saya ingin menguji fungsi pribadi, saya biasanya memodifikasinya untuk dilindungi, dan saya telah menulis subkelas dengan fungsi pembungkus publik.
Kelas:
Subclass untuk pengujian:
sumber
Saya pikir pertanyaan yang lebih mendasar yang harus ditanyakan adalah mengapa Anda mencoba untuk menguji metode pribadi di tempat pertama. Itu adalah bau kode yang Anda coba untuk menguji metode pribadi melalui antarmuka publik kelas itu sedangkan metode itu pribadi karena suatu alasan karena ini merupakan detail implementasi. Orang seharusnya hanya peduli dengan perilaku antarmuka publik bukan pada bagaimana itu diterapkan di bawah selimut.
Jika saya ingin menguji perilaku metode pribadi, dengan menggunakan refactoring umum, saya dapat mengekstrak kodenya ke kelas lain (mungkin dengan visibilitas tingkat paket jadi pastikan itu bukan bagian dari API publik). Saya kemudian dapat menguji perilakunya dalam isolasi.
Produk dari refactoring berarti bahwa metode pribadi sekarang menjadi kelas terpisah yang telah menjadi kolaborator dengan kelas asli. Perilakunya akan menjadi dipahami dengan baik melalui unit test sendiri.
Saya kemudian dapat mengejek perilakunya ketika saya mencoba menguji kelas asli sehingga saya kemudian dapat berkonsentrasi pada pengujian perilaku antarmuka publik kelas itu daripada harus menguji ledakan kombinatorial dari antarmuka publik dan perilaku semua metode privatnya. .
Saya melihat ini analog dengan mengendarai mobil. Ketika saya mengendarai mobil, saya tidak mengemudi dengan kap mesin sehingga saya dapat melihat bahwa mesinnya bekerja. Saya mengandalkan antarmuka yang disediakan mobil, yaitu penghitung putaran dan speedometer untuk mengetahui mesin bekerja. Saya mengandalkan kenyataan bahwa mobil itu benar-benar bergerak ketika saya menekan pedal gas. Jika saya ingin menguji mesin saya dapat melakukan pemeriksaan itu secara terpisah. : D
Tentu saja menguji metode pribadi secara langsung mungkin merupakan pilihan terakhir jika Anda memiliki aplikasi lawas tetapi saya lebih suka kode warisan itu direactored untuk memungkinkan pengujian yang lebih baik. Michael Feathers telah menulis buku yang bagus tentang hal ini. http://www.amazon.co.uk/Working-Effectively-Legacy-Robert-Martin/dp/0131177052
sumber
Jenis pribadi, internal, dan anggota pribadi begitu karena beberapa alasan, dan seringkali Anda tidak ingin mengacaukannya secara langsung. Dan jika Anda melakukannya, kemungkinan besar Anda akan melanggar kemudian, karena tidak ada jaminan bahwa orang-orang yang menciptakan majelis tersebut akan menjaga implementasi pribadi / internal seperti itu.
Tetapi, kadang-kadang, ketika melakukan beberapa peretasan / eksplorasi majelis yang dikompilasi atau pihak ketiga, saya sendiri akhirnya ingin menginisialisasi kelas privat atau kelas dengan konstruktor pribadi atau internal. Atau, kadang-kadang, ketika berhadapan dengan perpustakaan lawas yang sudah dikompilasi sebelumnya yang tidak dapat saya ubah - saya akhirnya menulis beberapa tes terhadap metode pribadi.
Maka lahirlah AccessPrivateWrapper - http://amazedsaint.blogspot.com/2010/05/accessprivatewrapper-c-40-dynamic.html - ini adalah kelas pembungkus cepat yang akan mempermudah pekerjaan menggunakan fitur dinamis C # 4.0 dan refleksi.
Anda dapat membuat tipe internal / pribadi seperti
sumber
Anda dapat menguji metode pribadi dengan dua cara
Anda dapat membuat instance dari
PrivateObject
kelas sintaksnya adalah sebagai berikutAnda bisa menggunakan refleksi.
sumber
PrivateClass
pertama dan menggunakannya. stackoverflow.com/questions/9122708/…Saya juga menggunakan metode InternalsVisibleToAttribute. Perlu disebutkan juga bahwa, jika Anda merasa tidak nyaman membuat metode yang sebelumnya pribadi Anda internal untuk mencapai ini, maka mungkin mereka seharusnya tidak menjadi subjek dari tes unit langsung.
Setelah semua, Anda menguji perilaku kelas Anda, daripada implementasi spesifik - Anda dapat mengubah yang terakhir tanpa mengubah yang pertama dan tes Anda masih harus lulus.
sumber
Ada 2 jenis metode pribadi. Metode Privat Statis dan Metode Privat Non Statis (Metode Instance). 2 artikel berikut menjelaskan cara unit menguji metode pribadi dengan contoh.
sumber
MS Test memiliki fitur bagus bawaan yang membuat anggota pribadi dan metode yang tersedia dalam proyek dengan membuat file yang disebut VSCodeGenAccessors
Dengan kelas yang berasal dari BaseAccessor
seperti
sumber
Pada CodeProject, ada sebuah artikel yang secara singkat membahas pro dan kontra dari pengujian metode pribadi. Kemudian memberikan beberapa kode refleksi untuk mengakses metode pribadi (mirip dengan kode yang diberikan Marcus di atas.) Satu-satunya masalah yang saya temukan dengan sampel adalah bahwa kode tidak memperhitungkan metode kelebihan beban akun.
Anda dapat menemukan artikelnya di sini:
http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx
sumber
Nyatakan
internal
, lalu gunakanInternalsVisibleToAttribute
untuk memungkinkan unit uji unit Anda melihatnya.sumber
Saya cenderung tidak menggunakan arahan kompiler karena mereka mengacaukan semuanya dengan cepat. Salah satu cara untuk memitigasinya jika Anda benar-benar membutuhkannya adalah dengan meletakkannya di kelas parsial dan membuat build Anda mengabaikan file .cs tersebut saat membuat versi produksi.
sumber
Anda seharusnya tidak menguji metode pribadi kode Anda di tempat pertama. Anda harus menguji 'antarmuka publik' atau API, hal-hal umum dari kelas Anda. API adalah semua metode publik yang Anda paparkan ke penelepon luar.
Alasannya adalah bahwa setelah Anda mulai menguji metode pribadi dan internal kelas Anda, Anda menggabungkan implementasi kelas Anda (hal-hal pribadi) ke tes Anda. Ini berarti bahwa ketika Anda memutuskan untuk mengubah detail implementasi Anda, Anda juga harus mengubah tes Anda.
Karena itu Anda harus menghindari penggunaan InternalsVisibleToAtrribute.
Berikut ini adalah pembicaraan hebat oleh Ian Cooper yang membahas hal ini: Ian Cooper: TDD, di mana semuanya salah
sumber
Terkadang, ada baiknya untuk menguji deklarasi pribadi. Pada dasarnya, kompiler hanya memiliki satu metode publik: Kompilasi (string outputFileName, params string [] sourceSFileNames). Saya yakin Anda mengerti bahwa akan sulit untuk menguji metode seperti itu tanpa menguji setiap deklarasi "tersembunyi"!
Itu sebabnya kami membuat Visual T #: untuk membuat tes lebih mudah. Ini adalah bahasa pemrograman .NET gratis (kompatibel dengan C # v2.0).
Kami telah menambahkan operator '.-'. Itu hanya berperilaku seperti '.' operator, kecuali Anda juga dapat mengakses deklarasi tersembunyi dari pengujian Anda tanpa mengubah apa pun dalam proyek yang diuji.
Lihatlah situs web kami: unduh secara gratis .
sumber
Saya terkejut belum ada yang mengatakan ini, tetapi solusi yang saya gunakan adalah membuat metode statis di dalam kelas untuk menguji sendiri. Ini memberi Anda akses ke semua publik dan pribadi untuk diuji.
Selanjutnya, dalam bahasa scripting (dengan kemampuan OO, seperti Python, Ruby dan PHP), Anda dapat membuat tes file itu sendiri saat dijalankan. Cara cepat yang bagus untuk memastikan perubahan Anda tidak merusak apa pun. Ini jelas membuat solusi scalable untuk menguji semua kelas Anda: jalankan saja semuanya. (Anda juga dapat melakukan ini dalam bahasa lain dengan void main yang selalu menjalankan tesnya juga).
sumber
Saya ingin membuat contoh kode yang jelas di sini yang dapat Anda gunakan pada kelas mana pun di mana Anda ingin menguji metode pribadi.
Di kelas ujian Anda, sertakan saja metode ini dan kemudian gunakan sesuai indikasi.
$ this -> _ callMethod ('_ someFunctionName', array (param1, param2, param3));
Hanya mengeluarkan parameter dalam urutan yang muncul di fungsi pribadi asli
sumber
Bagi siapa saja yang ingin menjalankan metode pribadi tanpa semua fess dan kekacauan. Ini berfungsi dengan kerangka pengujian unit apa pun yang menggunakan Refleksi lama yang bagus.
Kemudian dalam tes Anda yang sebenarnya, Anda dapat melakukan sesuatu seperti ini:
sumber
MbUnit punya pembungkus yang bagus untuk ini yang disebut Reflector.
Anda juga dapat mengatur dan mendapatkan nilai dari properti
Mengenai "tes pribadi" saya setuju itu .. di dunia yang sempurna. tidak ada gunanya melakukan tes unit pribadi. Tetapi di dunia nyata Anda mungkin ingin menulis tes pribadi alih-alih kode refactoring.
sumber
Reflector
telah digantikan oleh yang lebih kuatMirror
di Gallio / MbUnit v3.2. ( gallio.org/wiki/doku.php?id=mbunit:mirror )Berikut adalah artikel yang bagus tentang unit testing metode pribadi. Tapi saya tidak yakin apa yang lebih baik, untuk membuat Anda aplikasi yang dirancang khusus untuk pengujian (seperti membuat tes untuk pengujian saja) atau menggunakan refleksi untuk pengujian. Cukup yakin sebagian besar dari kita akan memilih cara kedua.
sumber
Menurut pendapat saya, Anda hanya harus menguji unit API publik kelas Anda.
Membuat metode publik, untuk menguji unit, istirahat enkapsulasi mengekspos detail implementasi.
API publik yang baik memecahkan tujuan langsung dari kode klien dan menyelesaikan tujuan itu sepenuhnya.
sumber
Saya menggunakan kelas PrivateObject . Tetapi seperti yang disebutkan sebelumnya lebih baik untuk menghindari pengujian metode pribadi.
sumber
"CC" adalah kompiler baris perintah pada sistem yang saya gunakan.
-Dfoo=bar
tidak sama dengan#define foo bar
. Jadi, opsi kompilasi ini secara efektif mengubah semua hal pribadi menjadi publik.sumber
Inilah sebuah contoh, pertama metode tanda tangan:
Inilah tesnya:
sumber
Cara untuk melakukan ini adalah dengan memiliki metode Anda
protected
dan menulis perlengkapan ujian yang mewarisi kelas Anda untuk diuji. Dengan cara ini, Anda tidak membalik metode Andapublic
, tetapi Anda mengaktifkan pengujian.sumber
1) Jika Anda memiliki kode lawas maka satu-satunya cara untuk menguji metode pribadi adalah dengan refleksi.
2) Jika kode baru maka Anda memiliki opsi berikut:
Saya lebih suka metode penjelasan, paling sederhana dan paling tidak rumit. Satu-satunya masalah adalah bahwa kami telah meningkatkan visibilitas yang saya pikir bukan masalah besar. Kita harus selalu mengkodekan ke antarmuka, jadi jika kita memiliki antarmuka MyService dan implementasi MyServiceImpl maka kita dapat memiliki kelas uji yang sesuai yaitu MyServiceTest (metode antarmuka uji) dan MyServiceImplTest (uji metode pribadi). Semua klien tetap harus menggunakan antarmuka sehingga dengan cara meskipun visibilitas metode pribadi telah ditingkatkan, itu seharusnya tidak terlalu menjadi masalah.
sumber
Anda juga dapat mendeklarasikannya sebagai publik atau internal (dengan InternalsVisibleToAttribute) saat membangun dalam Mode debug:
Itu menggembungkan kode, tetapi akan
private
dalam rilis rilissumber
Anda bisa membuat metode pengujian untuk metode pribadi dari Visual studio 2008. Ketika Anda membuat tes unit untuk metode pribadi, folder Referensi Referensi ditambahkan ke proyek pengujian Anda dan accessor ditambahkan ke folder itu. Accessor juga disebut dalam logika metode unit test. Accessor ini memungkinkan pengujian unit Anda untuk memanggil metode pribadi dalam kode yang Anda uji. Untuk detailnya lihat
http://msdn.microsoft.com/en-us/library/bb385974.aspx
sumber
Perhatikan juga bahwa InternalsVisibleToAtrribute memiliki persyaratan agar nama perakitan Anda kuat , yang menciptakan serangkaian masalah sendiri jika Anda bekerja dalam solusi yang belum memiliki persyaratan itu sebelumnya. Saya menggunakan accessor untuk menguji metode pribadi. Lihat pertanyaan ini sebagai contohnya.
sumber
InternalsVisibleToAttribute
itu tidak mengharuskan majelis Anda diberi nama kuat. Saat ini saya menggunakannya pada proyek di mana itu tidak terjadi.