Pengujian dengan semua dependensi yang ada masih penting, tetapi lebih pada ranah pengujian integrasi seperti yang dikatakan Jeffrey Faust.
Salah satu aspek terpenting dari unit testing adalah membuat tes Anda dapat dipercaya. Jika Anda tidak percaya bahwa tes kelulusan benar-benar berarti semuanya baik dan bahwa tes gagal benar-benar berarti masalah dalam kode produksi, tes Anda hampir tidak berguna seperti semula.
Agar tes Anda dapat dipercaya, Anda harus melakukan beberapa hal, tetapi saya akan fokus hanya pada satu untuk jawaban ini. Anda harus memastikan mereka mudah dijalankan, sehingga semua pengembang dapat dengan mudah menjalankannya sebelum memeriksa kode. "Mudah dijalankan" berarti tes Anda berjalan cepat dan tidak ada konfigurasi atau pengaturan yang luas yang diperlukan untuk membuatnya berjalan. Idealnya, siapa pun harus dapat melihat versi terbaru dari kode, menjalankan tes segera, dan melihatnya lulus.
Mengabstraksi ketergantungan pada hal-hal lain (sistem file, database, layanan web, dll.) Memungkinkan Anda untuk menghindari memerlukan konfigurasi dan membuat Anda dan pengembang lainnya kurang rentan terhadap situasi di mana Anda tergoda untuk mengatakan "Oh, tes gagal karena saya tidak "Saya sudah menyiapkan jaringan berbagi. Oh well. Saya akan jalankan nanti."
Jika Anda ingin menguji apa yang Anda lakukan dengan beberapa data, unit Anda menguji kode logika bisnis itu seharusnya tidak peduli bagaimana Anda mendapatkan data itu. Mampu menguji logika inti aplikasi Anda tanpa bergantung pada hal-hal yang mendukung seperti database itu mengagumkan. Jika Anda tidak melakukannya, Anda kehilangan.
PS Saya harus menambahkan bahwa itu pasti mungkin untuk overengineer atas nama testability. Menguji mengemudi aplikasi Anda membantu mengurangi itu. Namun bagaimanapun juga, implementasi pendekatan yang buruk tidak membuat pendekatan tersebut kurang valid. Apa pun dapat disalahgunakan dan dilakukan secara berlebihan jika seseorang tidak terus bertanya "mengapa saya melakukan ini?" saat berkembang.
Sejauh menyangkut ketergantungan internal, keadaan menjadi sedikit berlumpur. Cara saya suka memikirkannya adalah bahwa saya ingin melindungi kelas saya sebanyak mungkin dari perubahan karena alasan yang salah. Jika saya memiliki pengaturan seperti ini ...
public class MyClass
{
private SomeClass someClass;
public MyClass()
{
someClass = new SomeClass();
}
// use someClass in some way
}
Saya biasanya tidak peduli bagaimana SomeClass
dibuat. Saya hanya ingin menggunakannya. Jika SomeClass berubah dan sekarang memerlukan parameter untuk konstruktor ... itu bukan masalah saya. Saya tidak perlu mengubah MyClass untuk mengakomodasi itu.
Sekarang, itu hanya menyentuh pada bagian desain. Sejauh menyangkut tes unit, saya juga ingin melindungi diri dari kelas lain. Jika saya menguji MyClass, saya suka mengetahui fakta bahwa tidak ada dependensi eksternal, bahwa SomeClass pada suatu titik tidak memperkenalkan koneksi database atau beberapa tautan eksternal lainnya.
Tetapi masalah yang lebih besar adalah bahwa saya juga tahu bahwa beberapa hasil metode saya bergantung pada output dari beberapa metode pada SomeClass. Tanpa mengejek / mematikan SomeClass, saya mungkin tidak memiliki cara untuk memvariasikan input yang diminta. Jika saya beruntung, saya mungkin bisa menyusun lingkungan saya di dalam tes sedemikian rupa sehingga akan memicu respons yang tepat dari SomeClass, tetapi dengan cara itu memperkenalkan kompleksitas ke dalam tes saya dan membuatnya rapuh.
Menulis ulang MyClass untuk menerima turunan SomeClass di konstruktor memungkinkan saya untuk membuat turunan palsu dari SomeClass yang mengembalikan nilai yang saya inginkan (baik melalui kerangka kerja mengejek atau dengan tiruan manual). Saya biasanya tidak harus memperkenalkan antarmuka dalam hal ini. Apakah melakukannya atau tidak dalam banyak hal merupakan pilihan pribadi yang mungkin ditentukan oleh bahasa pilihan Anda (mis. Antarmuka lebih mungkin dalam C #, tetapi Anda pasti tidak akan membutuhkannya di Ruby).