Apakah injeksi ketergantungan penting untuk pengujian unit?

56

Apakah menggunakan injeksi ketergantungan (DI) penting untuk pengujian unit?

Saya tidak bisa memikirkan alternatif lain untuk mengisolasi kode sehingga dapat diuji. Juga, semua contoh yang pernah saya lihat menggunakan pola ini. Apakah itu karena itu satu-satunya pilihan yang layak atau apakah ada alternatif lain?

Tom Squires
sumber
5
Ketergantungan Injeksi tidak penting, tetapi konsep yang lebih luas dari Inversion of Control adalah.
Jeremy Heiler
Ada sesuatu yang bisa dikatakan untuk skala di sini. Jika saya memiliki basis kode kecil dengan sangat sedikit lapisan maka DI mungkin tidak berguna.
JB King
@JBKing jika Anda memiliki basis kode kecil Anda tidak perlu pengujian lapisan atau unit
Sklivvz
1
Banyak keputusan desain diperlukan untuk membuat kode Anda dapat diuji. Mulailah menulis tes dan temukan jawabannya.
Nathan Cooper

Jawaban:

43

DI membuat pengujian unit jauh lebih mudah. Tetapi Anda masih bisa menulis unit test tanpa DI. Banyak unit test telah ditulis sebelum DI menjadi luas. (Tentu saja, beberapa teknik yang digunakan ini identik atau sangat mirip dengan DI tanpa menyadarinya memiliki nama mewah :-)

Saya sendiri telah menggunakan banyak antarmuka dan pabrik misalnya sebelum belajar tentang DI. Nama kelas pabrik yang sebenarnya mungkin telah dibaca dari file konfigurasi, atau diteruskan ke SUT sebagai argumen.

Pendekatan lain adalah menggunakan lajang (atau data yang dapat diakses secara global pada umumnya). Ya, saya tahu ini tidak direkomendasikan oleh banyak orang (termasuk saya) secara umum. Masih mungkin layak dalam situasi tertentu, terutama jika singleton berisi data konfigurasi statis yang tidak spesifik kasus uji, tetapi berbeda antara produksi dan lingkungan pengujian. Tentu saja memiliki masalah yang diketahui, jadi DI lebih unggul jika Anda dapat menggunakannya. Tetapi seringkali (misalnya dalam sistem legacy) Anda tidak bisa.

Ngomong-ngomong, Bekerja Efektif Dengan Legacy Code menjelaskan banyak trik untuk mendapatkan kode legacy yang dicakup oleh tes. Banyak dari ini tidak bagus, dan tidak dimaksudkan sebagai solusi jangka panjang. Tetapi mereka memungkinkan Anda untuk membuat unit test pertama yang berharga ke sistem yang tidak dapat diuji ... yang memungkinkan Anda untuk memulai refactoring, dan akhirnya (antara lain) memperkenalkan DI.

Péter Török
sumber
Setuju, DI sangat berguna untuk mengejek objek. Tetapi ada banyak skenario di mana DI tidak berguna dalam pengujian.
Kemoda
@ Cemoda suka misalnya apa?
BЈовић
@VJovic Misalnya objek mandiri. Saya memikirkan metode yang mengambil beberapa argumen dan melakukan beberapa hal tetapi tidak tergantung pada komponen lain (sehingga tidak perlu untuk DI).
Kemoda
@ Cemoda Kedengarannya seperti Anda menggambarkan pemrograman fungsional, dan Anda menggunakan DI. Anda menyuntikkan dependensi Anda sebagai parameter metode.
Erik Dietrich
3
@ Huggie, mengapa detail implementasi bocor di sini? Ketergantungan yang disuntikkan biasanya tersembunyi di balik sebuah antarmuka, dan intinya adalah bahwa kelas klien tidak tahu - dan tidak peduli dengan - apakah implementasi sebenarnya dari ketergantungan ini adalah kelas produksi nyata atau tiruan. Instansiasi terjadi di luar kelas klien, hanya bisa melihat contoh siap pakai.
Péter Török
56

Decoupling sangat penting untuk pengujian unit. DI adalah cara yang bagus untuk mencapai decoupling.

nlawalker
sumber
17
Pernyataan yang sangat benar yang sama sekali tidak menjawab pertanyaan.
Travis
10

Bergantung pada teknologi yang Anda gunakan, Anda dapat mengisolasi dependensi tanpa menggunakan DI. Misalnya, di dunia .NET, Moles memungkinkan Anda untuk mengisolasi dependensi tanpa pola DI.

Yang mengatakan, saya percaya kerangka kerja isolasi ini ditulis dan ditujukan untuk situasi dalam kode Anda dengan dependensi eksternal (filesystem, database, dll). Artinya, fakta bahwa seseorang dapat melakukan ini tidak berarti dia harus melakukannya.

Ketergantungan injeksi memungkinkan pengujian unit, tetapi juga memungkinkan modifikasi perilaku objek tanpa mengubah kode objek tersebut (prinsip terbuka / tertutup). Jadi, bukan hanya kode yang dapat diuji, tetapi kode fleksibel yang dihasilkan. Saya secara umum menemukan bahwa ada korelasi yang kuat antara kode yang dapat dipertahankan / fleksibel dan kode yang dapat diuji.

Erik Dietrich
sumber
3
Atau Moles memungkinkan Anda berpikir Anda memiliki kode yang bersih dan dapat diuji karena Anda menguji melalui sihir.
Wyatt Barnett
@ WyattBarnett Ya, sangat benar. Tahi lalat memiliki kemampuan meringis membuat seseorang mengatakan "siapa yang butuh semua polimorfisme ini dan hal-hal terbuka / tertutup, sih?!?"
Erik Dietrich
1
Tahi lalat digantikan oleh palsu , dan dari halaman palsu "Kerangka kerja Fakes membantu pengembang membuat, memelihara, dan menyuntikkan implementasi dummy dalam pengujian unit mereka" Kedengarannya seperti DI bagi saya.
Masuk
1
@Sign Tautan Anda juga mengatakan, "Kerangka kerja Fakes dapat digunakan untuk shim metode .NET apa pun, termasuk metode non-virtual dan statis dalam tipe tersegel.". Fakta bahwa kerangka kerja isolasi dapat digunakan bersama dengan DI tidak berarti bahwa mereka adalah DI.
Erik Dietrich
4

Tidak, DI tidak penting untuk pengujian unit, tetapi sangat membantu.

Anda dapat menggunakan pabrik atau pelacak dan menguji seperti yang Anda lakukan dengan DI (hanya saja tidak elegan dan akan membutuhkan lebih banyak pengaturan).

Juga, Objek Mock akan menjadi penting dalam sistem lama di mana banyak panggilan didelegasikan ke fungsi bukan dependensi. (Objek Mock juga dapat digunakan secara luas dalam pengaturan yang tepat juga)

Mungkin ada pengaturan di mana pengujian hampir tidak mungkin. Tetapi ini tidak didasarkan pada apakah injeksi ketergantungan digunakan atau tidak.

smp7d
sumber
3

Tidak , injeksi ketergantungan tidak penting untuk pengujian unit.

Ketergantungan injeksi membantu jika Anda memiliki kelas yang membutuhkan turunan kelas-dependen untuk melakukan beberapa sub-pemrosesan. Alih-alih DI Anda dapat memisahkan logika bisnis-metode menjadi bagian data-gethering (yang tidak dapat diuji unit) dan bagian perhitungan yang dapat diuji unit.

Contoh (menggunakan DI) Implementasi ini tergantung pada Karyawan, Akun, ...

 bool hasPermissionToTransferMoney(Employee employee, Account from, Account to, Money amount)
 {
     if (amount > 100 && employee.isStudent())
        return false;
     if (to.getOwner().getFamiliyName() == employee.getFamilyName() && ...
        return false; // cannot transfer money to himself;
     ...
 }

Setelah pemisahan pengumpulan data dan perhitungan:

 bool hasPermissionToTransferMoney(Employee employee, Account from, Account to, Money amount)
 {
     return hasPermissionToTransferMoney(employee.isStudent(), employee.getFamilyName(), to.getOwner().getFamilyName(), ...);
 }

 // the actual permission calculation
 static bool hasPermissionToTransferMoney(boolean isStudent, string employeeFamilyName, string receiverFamilyName, ...)
     if (amount > 100 && isStudent)
        return false;
     if (receiverFamilyName == employeeFamiliyName && ...
        return false; // cannot transfer money to himself
     ...
 }

Bagian perhitungan dapat dengan mudah diuji tanpa injeksi ketergantungan.

k3b
sumber
1
  • Injeksi ketergantungan tidak penting untuk pengujian unit

  • Pembalikan kontrol di sisi lain sangat penting ketika Anda ingin menukar satu implementasi dengan yang lain.

CodeART
sumber
0

Ya, ada alternatif untuk penggunaan DI untuk isolasi.

Salah satu alternatif adalah menggunakan pabrik atau ServiceLocator yang dapat dikonfigurasi dari tes untuk mengembalikan objek tiruan alih-alih yang asli.

Lain adalah dengan menggunakan kerangka isolasi yang cocok atau alat mengejek. Alat semacam itu ada untuk hampir semua bahasa pemrograman modern (setidaknya untuk Java, C #, Ruby, dan Python). Mereka dapat mengisolasi kelas yang sedang diuji dari implementasi kelas / tipe lain, bahkan ketika kelas yang diuji secara langsung instantiates dependensinya.

Rogério
sumber