Apa keuntungan yang menentukan dari pengujian unit vs pengujian integrasi?
Itu dikotomi yang salah.
Pengujian unit dan pengujian integrasi memiliki dua tujuan yang serupa tetapi berbeda. Tujuan dari pengujian unit adalah untuk memastikan metode Anda bekerja. Secara praktis, unit test memastikan bahwa kode memenuhi kontrak yang digariskan oleh unit test. Ini jelas dalam cara unit test dirancang: mereka secara khusus menyatakan apa yang seharusnya dilakukan oleh kode , dan menyatakan bahwa kode melakukan itu.
Tes integrasi berbeda. Tes integrasi melatih interaksi antar komponen perangkat lunak. Anda dapat memiliki komponen perangkat lunak yang lulus semua tes mereka dan masih gagal tes integrasi karena mereka tidak berinteraksi dengan benar.
Namun, jika ada keuntungan yang menentukan untuk pengujian unit, inilah: pengujian unit jauh lebih mudah untuk dibuat, dan membutuhkan jauh lebih sedikit waktu dan usaha daripada tes integrasi. Ketika digunakan dengan benar, unit test mendorong pengembangan kode "testable", yang berarti hasil akhir akan lebih andal, lebih mudah dipahami, dan lebih mudah untuk dipelihara. Kode yang dapat diuji memiliki karakteristik tertentu, seperti API yang koheren, perilaku berulang, dan mengembalikan hasil yang mudah ditegaskan.
Tes integrasi lebih sulit dan lebih mahal, karena Anda sering membutuhkan ejekan yang rumit, pengaturan yang rumit, dan pernyataan yang sulit. Pada tingkat integrasi sistem tertinggi, bayangkan mencoba mensimulasikan interaksi manusia dalam UI. Seluruh sistem perangkat lunak dikhususkan untuk otomatisasi semacam itu. Dan itu adalah otomatisasi yang kita kejar; pengujian manusia tidak dapat diulang, dan tidak skala seperti pengujian otomatis.
Akhirnya, pengujian integrasi tidak memberikan jaminan tentang cakupan kode. Berapa banyak kombinasi loop kode, kondisi dan cabang yang Anda uji dengan tes integrasi Anda? Apakah kamu benar-benar tahu? Ada alat yang dapat Anda gunakan dengan unit test dan metode yang sedang diuji yang akan memberi tahu Anda berapa banyak cakupan kode yang Anda miliki, dan apa kompleksitas cyclomatic dari kode Anda. Tetapi mereka hanya benar-benar bekerja dengan baik di tingkat metode, di mana unit test hidup.
Jika tes Anda berubah setiap kali Anda refactor, itu masalah yang berbeda. Tes unit seharusnya tentang mendokumentasikan apa yang dilakukan perangkat lunak Anda, membuktikan bahwa ia melakukan itu, dan kemudian membuktikannya melakukannya lagi ketika Anda menolak implementasi yang mendasarinya. Jika API Anda berubah, atau Anda perlu metode Anda untuk berubah sesuai dengan perubahan dalam desain sistem, itulah yang seharusnya terjadi. Jika itu sering terjadi, pertimbangkan untuk menulis tes Anda terlebih dahulu, sebelum Anda menulis kode. Ini akan memaksa Anda untuk memikirkan keseluruhan arsitektur, dan memungkinkan Anda untuk menulis kode dengan API yang sudah ada.
Jika Anda menghabiskan banyak waktu menulis tes unit untuk kode sepele seperti
public string SomeProperty { get; set; }
maka Anda harus menguji kembali pendekatan Anda. Unit testing seharusnya menguji perilaku, dan tidak ada perilaku pada baris kode di atas. Namun, Anda telah membuat ketergantungan pada kode Anda di suatu tempat, karena properti itu hampir pasti akan dirujuk ke tempat lain dalam kode Anda. Alih-alih melakukan itu, pertimbangkan menulis metode yang menerima properti yang dibutuhkan sebagai parameter:
public string SomeMethod(string someProperty);
Sekarang metode Anda tidak memiliki ketergantungan pada sesuatu di luar dirinya sendiri, dan sekarang lebih dapat diuji, karena sepenuhnya mandiri. Memang, Anda tidak akan selalu bisa melakukan ini, tetapi itu memindahkan kode Anda ke arah yang lebih dapat diuji, dan kali ini Anda sedang menulis unit test untuk perilaku aktual.