Saya telah menemukan bahwa hanya ada 3 cara untuk menguji unit dependensi (mock / stub) yang statis di C # .NET:
Mengingat dua di antaranya tidak gratis dan satu belum mencapai rilis 1.0, mengejek hal-hal statis tidak terlalu mudah.
Apakah itu membuat metode statis dan "jahat" seperti itu (dalam pengertian pengujian unit)? Dan jika demikian, mengapa penyelamat ingin saya membuat sesuatu yang bisa statis, statis? (Dengan asumsi penyelamat tidak juga "jahat".)
Klarifikasi: Saya berbicara tentang skenario ketika Anda ingin menguji unit metode dan metode yang memanggil metode statis di unit / kelas yang berbeda . Dengan sebagian besar definisi pengujian unit, jika Anda membiarkan metode yang sedang diuji memanggil metode statis di unit / kelas lain maka Anda bukan pengujian unit, Anda adalah pengujian integrasi . (Berguna, tetapi bukan tes unit.)
sumber
Jawaban:
Melihat jawaban lain di sini, saya pikir mungkin ada beberapa kebingungan antara metode statis yang tahan keadaan statis atau menyebabkan efek samping (yang menurut saya seperti ide yang sangat buruk), dan metode statis yang hanya mengembalikan nilai.
Metode statis yang tidak tahan dan tidak menimbulkan efek samping harus mudah diuji unit. Bahkan, saya menganggap metode semacam itu sebagai bentuk pemrograman fungsional "orang miskin"; Anda memberikan metode objek atau nilai, dan itu mengembalikan objek atau nilai. Tidak ada lagi. Saya tidak melihat bagaimana metode seperti itu akan mempengaruhi pengujian unit sama sekali.
sumber
Anda tampaknya membingungkan data statis dan metode statis . Resharper, jika saya ingat dengan benar, merekomendasikan membuat
private
metode dalam kelas statis jika dapat dibuat demikian - saya percaya ini menghasilkan manfaat kinerja yang kecil. Ini tidak merekomendasikan membuat "sesuatu yang dapat" statis!Tidak ada yang salah dengan metode statis dan mudah diuji (selama tidak mengubah data statis). Sebagai contoh, pikirkan perpustakaan Matematika, yang merupakan kandidat yang baik untuk kelas statis dengan metode statis. Jika Anda memiliki metode (dibuat-buat) seperti ini:
maka ini sangat dapat diuji dan tidak memiliki efek samping. Anda hanya memeriksa bahwa ketika Anda lulus, katakanlah, 20 Anda mendapatkan kembali 400. Tidak masalah.
sumber
System.Math
) belum lagi kelimpahan metode pabrik statis dll. Plus Anda tidak akan pernah dapat menggunakan metode ekstensi dll. Faktanya adalah, fungsi sederhana seperti ini adalah mendasar untuk bahasa modern. Anda dapat menguji ini secara terpisah (karena umumnya akan bersifat deterministik) dan kemudian menggunakannya di kelas Anda tanpa khawatir. Itu bukan masalah!Jika pertanyaan sebenarnya di sini adalah "Bagaimana cara menguji kode ini?":
Kemudian, cukup refactor kode dan menyuntikkan seperti biasa panggilan ke kelas statis seperti ini:
sumber
Statika tidak selalu jahat, tetapi mereka dapat membatasi pilihan Anda ketika datang ke pengujian unit dengan palsu / mengolok-olok / bertopik.
Ada dua pendekatan umum untuk mengejek.
Yang pertama (tradisional - dilaksanakan oleh RhinoMocks, Moq, NMock2; mengolok-olok manual dan bertopik juga di kamp ini) bergantung pada jahitan uji dan injeksi ketergantungan. Misalkan Anda sedang menguji beberapa kode statis dan memiliki dependensi. Apa yang sering terjadi dalam kode yang dirancang dengan cara ini adalah statika menciptakan dependensi mereka sendiri, membalikkan inversi dependensi . Anda segera menemukan bahwa Anda tidak dapat menyuntikkan antarmuka tiruan ke dalam kode yang sedang diuji yang dirancang dengan cara ini.
Yang kedua (mengejek apa pun - diimplementasikan oleh TypeMock, JustMock dan Moles) bergantung pada .NET's Profileing API . Itu dapat mencegat salah satu instruksi CIL Anda dan mengganti sepotong kode Anda dengan yang palsu. Ini memungkinkan TypeMock dan produk lain di kamp ini untuk mengolok-olok apa pun: statika, kelas tertutup, metode pribadi - hal-hal yang tidak dirancang untuk dapat diuji.
Ada perdebatan yang sedang berlangsung antara dua aliran pemikiran. Seseorang mengatakan, ikuti prinsip - prinsip dan desain SOLID untuk testabilitas (yang sering termasuk statika mudah). Yang lain mengatakan, beli TypeMock dan jangan khawatir.
sumber
Lihat ini: "Metode Statis adalah Kematian untuk Testabilitas" . Ringkasan singkat argumen:
Untuk menguji unit Anda perlu mengambil sepotong kecil kode Anda, rewire dependensi dan mengujinya secara terpisah. Ini sulit dengan metode statis, tidak hanya dalam kasus mereka mengakses keadaan global tetapi bahkan jika mereka hanya memanggil metode statis lainnya.
sumber
Kebenaran sederhana yang jarang diakui adalah bahwa jika sebuah kelas berisi ketergantungan kompiler-terlihat pada kelas lain, itu tidak dapat diuji secara terpisah dari kelas itu. Anda dapat memalsukan sesuatu yang terlihat seperti tes, dan akan muncul pada laporan seolah-olah itu adalah tes.
Tapi itu tidak akan memiliki sifat penentu utama dari suatu tes; gagal ketika ada sesuatu yang salah, melewati ketika mereka benar.
Ini berlaku untuk panggilan statis, panggilan konstruktor, dan referensi apa pun untuk metode atau bidang yang tidak diwarisi dari kelas dasar atau antarmuka . Jika nama kelas muncul dalam kode, itu adalah ketergantungan kompiler-terlihat, dan Anda tidak dapat menguji tanpa itu. Setiap potongan yang lebih kecil bukan merupakan unit yang dapat diuji valid . Setiap upaya untuk memperlakukannya seolah-olah akan memiliki hasil yang tidak lebih bermakna daripada menulis sedikit utilitas untuk memancarkan XML yang digunakan oleh kerangka pengujian Anda untuk mengatakan 'lulus uji'.
Mengingat bahwa, ada tiga opsi:
mendefinisikan pengujian unit untuk menguji unit yang terdiri dari kelas dan itu dependensi hard-coded. Ini berfungsi, asalkan Anda menghindari ketergantungan sirkular.
jangan pernah membuat dependensi waktu kompilasi antara kelas yang Anda bertanggung jawab untuk pengujian. Ini berfungsi, asalkan Anda tidak keberatan dengan gaya kode yang dihasilkan.
jangan uji unit, tes integrasi sebagai gantinya. Yang berfungsi, asalkan tidak bertentangan dengan hal lain yang Anda perlukan untuk menggunakan pengujian integrasi istilah.
sumber
Math.Pi
dalam suatu metode tidak menjadikannya sebagai tes integrasi dengan definisi yang masuk akal.Tidak ada dua cara tentang itu. Saran ReSharper dan beberapa fitur berguna dari C # tidak akan digunakan sesering jika Anda menulis tes unit atom terisolasi untuk semua kode Anda.
Misalnya, jika Anda memiliki metode statis dan Anda harus mematikannya, Anda tidak bisa kecuali Anda menggunakan kerangka kerja isolasi berbasis profil. Pemecahan masalah yang kompatibel dengan panggilan adalah mengubah bagian atas metode untuk menggunakan notasi lambda. Sebagai contoh:
SEBELUM:
SETELAH:
Keduanya kompatibel dengan panggilan. Penelepon tidak harus berubah. Tubuh fungsi tetap sama.
Kemudian dalam kode Unit-Test Anda, Anda dapat mematikan panggilan ini seperti itu (dengan asumsi itu dalam kelas yang disebut Database):
Berhati-hatilah untuk menggantinya dengan nilai asli setelah Anda selesai. Anda dapat melakukannya melalui percobaan / akhirnya atau, dalam pembersihan unit-tes Anda, tes yang dipanggil setelah setiap tes, tulis kode seperti ini:
yang akan memanggil kembali initializer statis kelas Anda.
Fungsi Lambda tidak terlalu kaya dalam dukungan seperti metode statis biasa, sehingga pendekatan ini memiliki efek samping yang tidak diinginkan:
Tetapi katakanlah Anda menghindari statika sama sekali, dan Anda mengonversinya menjadi metode instan. Itu masih tidak bisa dipermainkan kecuali metode ini virtual atau diimplementasikan sebagai bagian dari antarmuka.
Jadi pada kenyataannya, siapa pun yang menyarankan solusi untuk mematikan metode statis adalah menjadikannya metode instan, mereka juga akan menentang metode instan yang bukan virtual atau bagian dari antarmuka.
Jadi mengapa C # memiliki metode statis? Mengapa ini memungkinkan metode instance non-virtual?
Jika Anda menggunakan salah satu dari "Fitur" ini, maka Anda tidak dapat membuat metode yang terisolasi.
Jadi kapan Anda menggunakannya?
Gunakan mereka untuk kode apa pun yang Anda tidak harapkan ada orang yang ingin mematikannya. Beberapa contoh: metode Format () dari kelas String metode WriteLine () dari kelas Konsol metode Cosh () dari kelas Matematika
Dan satu hal lagi .. Kebanyakan orang tidak akan peduli tentang ini, tetapi jika Anda bisa tentang kinerja panggilan tidak langsung, itu alasan lain untuk menghindari metode instan. Ada kasus ketika itu adalah hit kinerja. Itu sebabnya metode non-virtual ada di tempat pertama.
sumber
R # bukan satu-satunya alat yang akan membuat saran ini. Analisis Kode FxCop / MS juga akan melakukan hal yang sama.
Saya biasanya akan mengatakan bahwa jika metode ini statis, umumnya harus dapat diuji juga. Itu membawa beberapa pertimbangan desain dan mungkin lebih banyak diskusi daripada yang saya miliki di jari saya sekarang, jadi dengan sabar menunggu suara turun dan komentar ...;)
sumber
Saya melihat bahwa setelah lama tidak ada yang menyatakan fakta yang sangat sederhana. Jika resharper mengatakan kepada saya bahwa saya dapat membuat metode statis, itu berarti hal yang sangat besar bagi saya, saya dapat mendengar suaranya mengatakan kepada saya: "hei, kamu, potongan-potongan logika ini bukan TANGGUNG JAWAB kelas saat ini untuk ditangani, jadi harus tetap di luar di beberapa kelas pembantu atau sesuatu ".
sumber
Jika metode statis dipanggil dari dalam metode lain , tidak mungkin untuk mencegah atau mengganti panggilan semacam itu. Ini berarti, kedua metode ini membuat Unit tunggal; Unit test jenis apa pun menguji keduanya.
Dan jika metode statis ini berbicara ke Internet, menghubungkan basis data, menampilkan popup GUI atau mengonversi uji Unit menjadi kekacauan total, itu hanya dilakukan tanpa ada penyelesaian yang mudah. Sebuah metode yang memanggil metode statis seperti itu tidak dapat diuji tanpa refactoring, bahkan jika ia memiliki banyak kode komputasi murni yang akan sangat diuntungkan dengan menjadi unit yang diuji.
sumber
Saya percaya bahwa Resharper memberi Anda petunjuk dan menerapkan pedoman pengkodean yang telah disiapkan. Ketika saya telah menggunakan Resharper dan telah memberi tahu saya bahwa suatu metode harus statis itu terikat pada metode pribadi yang tidak bertindak pada variabel contoh apa pun.
Sekarang untuk testablity skenario ini seharusnya tidak menjadi masalah karena Anda tidak harus menguji metode pribadi.
Sedangkan untuk pengujian metode statis yang bersifat publik maka pengujian unit menjadi sulit ketika metode statis menyentuh keadaan statis. Secara pribadi saya akan menjaga ini seminimal mungkin dan menggunakan metode statis sebagai fungsi murni sebanyak mungkin di mana setiap dependensi dilewatkan ke dalam metode yang dapat dikontrol melalui perlengkapan uji. Namun ini adalah keputusan desain.
sumber