Saya percaya ini adalah kesalahpahaman dengan cara apa pun yang dapat saya pikirkan.
Kode uji yang menguji kode produksi sama sekali tidak sama. Saya akan menunjukkan dengan python:
def multiply(a, b):
"""Multiply ``a`` by ``b``"""
return a*b
Maka tes sederhana adalah:
def test_multiply():
assert multiply(4, 5) == 20
Kedua fungsi memiliki definisi yang sama tetapi keduanya melakukan hal yang sangat berbeda. Tidak ada kode duplikat di sini. ;-)
Itu juga terjadi bahwa orang menulis tes duplikat pada dasarnya memiliki satu pernyataan per fungsi tes. Ini kegilaan dan saya telah melihat orang-orang melakukan ini. Ini adalah praktik yang buruk.
def test_multiply_1_and_3():
"""Assert that a multiplication of 1 and 3 is 3."""
assert multiply(1, 3) == 3
def test_multiply_1_and_7():
"""Assert that a multiplication of 1 and 7 is 7."""
assert multiply(1, 7) == 7
def test_multiply_3_and_4():
"""Assert that a multiplication of 3 and 4 is 12."""
assert multiply(3, 4) == 12
Bayangkan melakukan ini untuk 1000+ baris kode yang efektif. Alih-alih, Anda menguji berdasarkan per 'fitur':
def test_multiply_positive():
"""Assert that positive numbers can be multiplied."""
assert multiply(1, 3) == 3
assert multiply(1, 7) == 7
assert multiply(3, 4) == 12
def test_multiply_negative():
"""Assert that negative numbers can be multiplied."""
assert multiply(1, -3) == -3
assert multiply(-1, -7) == 7
assert multiply(-3, 4) == -12
Sekarang ketika fitur ditambahkan / dihapus saya hanya perlu mempertimbangkan untuk menambah / menghapus satu fungsi tes.
Anda mungkin telah memperhatikan saya belum menerapkan for
loop. Ini karena mengulangi beberapa hal itu baik. Ketika saya akan menerapkan loop kode akan jauh lebih pendek. Tetapi ketika sebuah pernyataan gagal, itu bisa mengaburkan keluaran yang menampilkan pesan yang ambigu. Jika ini terjadi maka pengujian Anda akan kurang bermanfaat dan Anda akan memerlukan debugger untuk memeriksa kesalahan yang terjadi.
assert multiply(1,3)
akan gagal tetapi Anda juga tidak akan mendapatkan laporan pengujian yang gagalassert multiply(3,4)
.def test_shuffle
melakukan dua menegaskan.assert multiply(*, *) == *
sehingga Anda dapat mendefinisikan suatuassert_multiply
fungsi. Dalam skenario saat ini tidak masalah dengan jumlah baris dan keterbacaan, tetapi dengan tes yang lebih lama Anda dapat menggunakan kembali pernyataan yang rumit, perlengkapan, kode penghasil fixture, dll ... Saya tidak tahu apakah ini adalah praktik terbaik, tapi biasanya saya lakukan ini.Tidak, ini tidak benar.
Tes memiliki tujuan yang berbeda dari implementasi Anda:
sumber
Tidak. KERING adalah tentang menulis kode sekali saja untuk melakukan tugas tertentu, tes adalah validasi bahwa tugas tersebut dilakukan dengan benar. Ini agak mirip dengan algoritma pemungutan suara, di mana jelas menggunakan kode yang sama akan sia-sia.
sumber
Tidak, target akhir KERING sebenarnya berarti penghapusan semua kode produksi .
Jika pengujian kami dapat menjadi spesifikasi sempurna dari apa yang kami ingin sistem lakukan, kami hanya perlu membuat kode produksi yang sesuai (atau binari) secara otomatis, secara efektif menghapus basis kode produksi per se.
Inilah sebenarnya yang didekati oleh pendekatan yang ingin dicapai oleh arsitektur model-didorong - satu sumber kebenaran yang dirancang manusia dari mana segala sesuatu berasal dari perhitungan.
Saya tidak berpikir kebalikannya (menyingkirkan semua tes) diinginkan karena:
sumber
Karena terkadang mengulangi diri sendiri tidak apa-apa. Tidak satu pun dari prinsip-prinsip ini dimaksudkan untuk diambil dalam setiap keadaan tanpa pertanyaan atau konteks. Kadang-kadang saya memiliki tes tertulis terhadap versi algoritma yang naif (dan lambat), yang merupakan pelanggaran DRY yang cukup jelas, tetapi jelas bermanfaat.
sumber
Karena pengujian unit adalah tentang membuat perubahan yang tidak disengaja lebih sulit, kadang-kadang dapat membuat perubahan yang disengaja lebih sulit juga. Fakta ini memang terkait dengan prinsip KERING.
Misalnya, jika Anda memiliki fungsi
MyFunction
yang disebut dalam kode produksi hanya di satu tempat, dan Anda menulis 20 unit tes untuk itu, Anda dapat dengan mudah memiliki 21 tempat di kode Anda di mana fungsi itu dipanggil. Sekarang, ketika Anda harus mengubah tanda tanganMyFunction
, atau semantik, atau keduanya (karena beberapa persyaratan berubah), Anda memiliki 21 tempat untuk berubah, bukan hanya satu. Dan alasannya memang melanggar prinsip KERING: Anda mengulangi (setidaknya) panggilan fungsi yang sama hinggaMyFunction
21 kali.Pendekatan yang benar untuk kasus seperti itu adalah menerapkan prinsip KERING ke kode pengujian Anda juga: ketika menulis 20 unit tes, merangkum panggilan ke
MyFunction
dalam unit test Anda hanya dalam beberapa fungsi pembantu (idealnya hanya satu), yang digunakan oleh 20 unit tes. Idealnya, Anda hanya memiliki dua tempat dalam pemanggilan kode AndaMyFunction
: satu dari kode produksi Anda, dan satu dari Anda unit test. Jadi, ketika Anda harus mengubah tanda tanganMyFunction
nanti, Anda hanya akan memiliki beberapa tempat untuk berubah dalam tes Anda."Beberapa tempat" masih lebih dari "satu tempat" (apa yang Anda dapatkan tanpa tes unit sama sekali), tetapi keuntungan memiliki tes unit harus jauh lebih besar daripada keuntungan memiliki lebih sedikit kode untuk diubah (jika tidak, Anda melakukan pengujian unit secara lengkap salah).
sumber
Salah satu tantangan terbesar untuk membangun perangkat lunak adalah untuk menangkap persyaratan; itu untuk menjawab pertanyaan, "apa yang harus dilakukan perangkat lunak ini?" Perangkat lunak membutuhkan persyaratan yang tepat untuk secara akurat mendefinisikan apa yang perlu dilakukan sistem, tetapi mereka yang mendefinisikan kebutuhan untuk sistem dan proyek perangkat lunak sering kali menyertakan orang yang tidak memiliki latar belakang perangkat lunak atau formal (matematika). Kurangnya ketelitian dalam definisi persyaratan memaksa pengembangan perangkat lunak untuk menemukan cara untuk memvalidasi perangkat lunak sesuai persyaratan.
Tim pengembang menemukan diri mereka menerjemahkan deskripsi sehari-hari untuk proyek menjadi persyaratan yang lebih ketat. Disiplin pengujian telah bersatu sebagai titik pemeriksaan untuk pengembangan perangkat lunak, untuk menjembatani kesenjangan antara apa yang pelanggan katakan mereka inginkan, dan perangkat lunak apa yang mengerti yang mereka inginkan. Baik pengembang perangkat lunak dan tim kualitas / pengujian membentuk pemahaman tentang spesifikasi (informal), dan masing-masing (secara mandiri) menulis perangkat lunak atau tes untuk memastikan bahwa pemahaman mereka sesuai. Menambahkan orang lain untuk memahami persyaratan (tidak tepat) menambahkan pertanyaan dan perspektif yang berbeda untuk lebih mengasah ketepatan persyaratan.
Karena selalu ada pengujian penerimaan, wajar untuk memperluas peran pengujian untuk menulis pengujian otomatis dan unit. Masalahnya adalah itu berarti merekrut programmer untuk melakukan pengujian, dan dengan demikian Anda mempersempit perspektif dari jaminan kualitas untuk programmer melakukan pengujian.
Itu semua mengatakan, Anda mungkin melakukan pengujian yang salah jika tes Anda sedikit berbeda dari program yang sebenarnya. Saran Msdy adalah lebih fokus pada apa yang ada di tes, dan lebih sedikit pada bagaimana.
Ironisnya adalah bahwa daripada menangkap spesifikasi formal persyaratan dari deskripsi sehari-hari, industri telah memilih untuk menerapkan tes titik sebagai kode untuk mengotomatisasi pengujian. Daripada menghasilkan persyaratan formal yang perangkat lunak dapat dibangun untuk menjawab, pendekatan yang diambil adalah untuk menguji beberapa poin, daripada pendekatan membangun perangkat lunak menggunakan logika formal. Ini adalah kompromi, tetapi telah cukup efektif dan relatif berhasil.
sumber
Jika Anda merasa kode pengujian Anda terlalu mirip dengan kode implementasi Anda, ini mungkin merupakan indikasi bahwa Anda terlalu banyak menggunakan kerangka kerja mengejek. Pengujian berbasis mock pada level yang terlalu rendah dapat berakhir dengan pengaturan pengujian yang sangat mirip dengan metode yang sedang diuji. Cobalah untuk menulis tes tingkat yang lebih tinggi yang cenderung rusak jika Anda mengubah implementasi Anda (saya tahu ini bisa sulit, tetapi jika Anda bisa mengelolanya Anda akan memiliki test suite yang lebih berguna sebagai hasilnya).
sumber
Tes unit tidak boleh menyertakan duplikasi kode yang sedang diuji, seperti yang telah dicatat.
Saya akan menambahkan, bahwa, unit test biasanya tidak KERING seperti kode "produksi", karena setup cenderung serupa (tetapi tidak identik) di tes ... terutama jika Anda memiliki sejumlah besar dependensi yang Anda mengejek / berpura-pura.
Tentu saja mungkin untuk memperbaiki hal semacam ini menjadi metode pengaturan umum (atau serangkaian metode pengaturan) ... tetapi saya telah menemukan bahwa metode pengaturan tersebut cenderung memiliki daftar parameter yang panjang dan agak rapuh.
Jadi bersikaplah pragmatis. Jika Anda dapat mengkonsolidasikan kode pengaturan tanpa mengurangi perawatan, dengan cara apa pun melakukannya. Tetapi jika alternatifnya adalah serangkaian metode pengaturan yang kompleks dan rapuh, sedikit pengulangan dalam metode pengujian Anda OK.
Seorang penginjil lokal TDD / BDD menyatakan seperti ini:
"Kode produksi Anda harus KERING. Tapi tidak apa-apa untuk pengujian Anda menjadi 'lembab'."
sumber
Ini tidak benar, tes menggambarkan use case, sedangkan kode menggambarkan algoritma yang melewati use case, jadi mana yang lebih umum. Dengan TDD Anda mulai dengan menulis use case (mungkin berdasarkan kisah pengguna) dan setelah itu Anda mengimplementasikan kode yang diperlukan untuk melewati use case ini. Jadi Anda menulis tes kecil, sepotong kecil kode, dan setelah itu Anda refactor jika perlu untuk menyingkirkan pengulangan. Begitulah cara kerjanya.
Dengan tes bisa ada pengulangan juga. Misalnya Anda dapat menggunakan kembali perlengkapan, kode penghasil fixture, pernyataan rumit, dll ... Saya biasanya melakukan ini, untuk mencegah bug dalam tes, tetapi saya biasanya lupa untuk menguji dulu apakah tes benar-benar gagal, dan itu dapat benar-benar merusak hari. , ketika Anda mencari bug dalam kode selama setengah jam dan tes salah ... xD
sumber