Unit menguji beberapa kondisi dalam pernyataan IF

26

Saya memiliki sejumlah kode yang terlihat seperti ini:

function bool PassesBusinessRules()
{
    bool meetsBusinessRules = false;

    if (PassesBusinessRule1 
         && PassesBusinessRule2
         && PassesBusinessRule3)
    {
         meetsBusinessRules= true;
    }

    return meetsBusinessRules;
}

Saya percaya harus ada empat unit tes untuk fungsi khusus ini. Tiga untuk menguji setiap kondisi dalam pernyataan if dan memastikan itu mengembalikan false. Dan tes lain yang memastikan fungsi kembali benar.

Pertanyaan: Haruskah sebenarnya ada sepuluh unit test saja? Sembilan yang memeriksa masing-masing jalur kegagalan yang mungkin. YAITU:

  • False False False
  • False False Benar
  • False Benar False

Dan seterusnya untuk setiap kemungkinan kombinasi.

Saya pikir itu berlebihan, tetapi beberapa anggota lain di tim saya tidak. Cara saya melihatnya adalah jika BusinessRule1 gagal maka itu harus selalu mengembalikan false, tidak masalah jika diperiksa pertama atau terakhir.

bwalk2895
sumber
Apakah kompiler menggunakan evaluasi serakah untuk operator &&?
suszterpatt
12
Jika Anda menulis 10 pengujian unit, Anda akan menguji && operator, bukan metode Anda.
Mert Akcakaya
2
Bukankah hanya ada delapan tes jika Anda menguji semua kemungkinan kombinasi? Tiga parameter boolean dihidupkan atau dimatikan.
Kris Harper
3
@Mert: Hanya jika Anda dapat menjamin bahwa && akan selalu ada di sana.
Misko
Hickey: Jika kita menghabiskan waktu menulis tes, itu saatnya kita tidak menghabiskan melakukan sesuatu yang lain. Masing-masing dari kita perlu menilai cara terbaik untuk menghabiskan waktu kita untuk memaksimalkan hasil kita, baik secara kuantitas dan kualitas. Jika orang berpikir bahwa menghabiskan lima puluh persen dari waktu mereka menulis tes memaksimalkan hasil mereka — oke untuk mereka. Saya yakin itu tidak benar untuk saya — saya lebih suka menghabiskan waktu memikirkan masalah saya. Saya yakin, bagi saya, ini menghasilkan solusi yang lebih baik, dengan lebih sedikit cacat, daripada penggunaan waktu saya yang lain. Desain yang buruk dengan test suite yang lengkap masih merupakan desain yang buruk.
Ayub

Jawaban:

29

Secara formal, jenis liputan tersebut memiliki nama.

Pertama, ada cakupan predikat : Anda ingin memiliki test case yang membuat pernyataan if benar, dan yang membuatnya salah. Memiliki cakupan ini dipenuhi mungkin merupakan persyaratan dasar untuk test suite yang baik.

Lalu ada Ketentuan Cakupan : Di sini Anda ingin menguji bahwa setiap sub-kondisi di if memiliki nilai true dan false. Ini jelas membuat lebih banyak tes, tetapi biasanya menangkap lebih banyak bug, jadi sering kali merupakan ide yang baik untuk disertakan dalam test suite Anda jika Anda punya waktu.

Kriteria cakupan paling maju biasanya disebut Cakupan Kondisi Kombinatorial : Di sini tujuannya adalah untuk memiliki test case yang melewati semua kemungkinan kombinasi nilai boolean dalam pengujian Anda.

Apakah ini lebih baik daripada predikat sederhana atau ketentuan cakupan? Dalam hal liputan, tentu saja. Tapi itu tidak gratis. Itu datang dengan biaya yang sangat tinggi dalam pemeliharaan uji. Untuk alasan ini, kebanyakan orang tidak peduli dengan cakupan kombinatorial penuh. Biasanya menguji semua cabang (atau semua kondisi), akan cukup baik untuk menangkap bug. Menambahkan tes tambahan untuk pengujian kombinatorial biasanya tidak akan menangkap lebih banyak bug, tetapi membutuhkan banyak upaya untuk membuat dan memelihara. Upaya ekstra biasanya membuat ini tidak sebanding dengan hasil yang sangat kecil, jadi saya tidak akan merekomendasikan ini.

Bagian dari keputusan ini harus didasarkan pada seberapa berisiko menurut Anda kode itu. Jika memiliki banyak ruang untuk gagal, layak untuk diuji. Jika agak stabil, dan tidak akan banyak berubah, Anda harus mempertimbangkan memfokuskan upaya pengujian Anda di tempat lain.

Oleksi
sumber
2
Jika nilai boolean dilewatkan dari sumber eksternal (artinya mereka tidak selalu divalidasi), maka cakupan kondisional kombinatorial sering diperlukan. Pertama buat tabel kombinasi. Kemudian, untuk setiap entri, putuskan apakah entri tersebut mewakili use case yang bermakna. Jika tidak, harus ada kode di suatu tempat (pernyataan perangkat lunak atau klausa validasi) untuk mencegah kombinasi tersebut dieksekusi. Penting untuk tidak mengelompokkan semua parameter dalam uji kombinatorial tunggal: cobalah mempartisi parameter ke dalam kelompok yang berinteraksi satu sama lain, yaitu berbagi ekspresi boolean yang sama.
rwong
Seberapa yakin Anda dengan ketentuan yang berani? Jawaban Anda tampaknya menjadi satu-satunya kemunculan "Cakupan Kondisi Kombinatorial", dan beberapa sumber mengatakan bahwa "cakupan predikat" dan "cakupan bersyarat" adalah hal yang sama.
Stijn
8

Pada akhirnya, itu tergantung pada Anda (tim r), kode dan lingkungan proyek tertentu. Tidak ada aturan universal. Anda (tim) harus menulis sebanyak mungkin tes yang Anda butuhkan untuk merasa nyaman bahwa kode itu memang benar . Jadi, jika rekan tim Anda tidak yakin dengan 4 tes, mungkin Anda perlu lebih banyak.

Waktu OTOH untuk menulis unit test biasanya merupakan sumber daya yang langka. Jadi usahakan untuk menemukan cara terbaik untuk menghabiskan waktu terbatas yang Anda miliki . Misalnya, jika Anda memiliki metode penting lain dengan cakupan 0%, mungkin lebih baik untuk menulis beberapa tes unit untuk membahasnya, daripada menambahkan tes tambahan untuk metode ini. Tentu saja, itu juga tergantung pada seberapa rapuh implementasi masing-masing. Merencanakan banyak perubahan pada metode khusus ini di masa mendatang dapat membenarkan cakupan tes unit tambahan. Jadi mungkin berada di jalur kritis di dalam program. Ini semua adalah faktor yang hanya Anda (tim r) yang dapat menilai.

Saya pribadi biasanya akan senang dengan 4 tes yang Anda buat, yaitu:

  • benar salah salah
  • false true false
  • false false benar
  • betul betul betul

plus mungkin satu:

  • benar benar salah

untuk memastikan bahwa satu-satunya cara untuk mendapatkan nilai pengembalian trueadalah dengan memenuhi semua 3 aturan bisnis. Tetapi pada akhirnya, jika rekan setim Anda bersikeras agar jalur kombinatorial tertutup, mungkin lebih murah untuk menambahkan tes tambahan daripada melanjutkan argumen lebih lama :-)

Péter Török
sumber
3

Jika Anda ingin aman, Anda akan membutuhkan delapan unit tes menggunakan kondisi yang diwakili oleh tabel kebenaran tiga variabel ( http://teach.valdosta.edu/plmoch/MATH4161/Spring%202004/and_or_if_files/image006.gif ).

Anda tidak pernah bisa yakin bahwa logika bisnis akan selalu menetapkan bahwa pemeriksaan dilakukan dalam urutan itu dan Anda ingin tes mengetahui sesedikit mungkin tentang implementasi yang sebenarnya.

smp7d
sumber
2
Pengujian unit adalah pengujian kotak putih.
Péter Török
Agar tertib tidak menjadi masalah, && bersifat komunikatif, atau setidaknya seharusnya
Zachary K
2

Ya, harus ada kombinasi penuh di dunia yang ideal.

Saat melakukan tes unit, Anda harus benar-benar mencoba mengabaikan cara kerjanya. Cukup sediakan 3 input dan verifikasi bahwa output sudah benar.

Telastyn
sumber
1
Pengujian unit adalah pengujian kotak putih. Dan kita tidak hidup di dunia yang ideal.
Péter Török
@ PéterTörök - Kami tidak hidup di dunia yang ideal untuk memastikan, tetapi stackexchange tidak setuju dengan Anda di titik lain. Khusus untuk TDD, tes ditulis sesuai spesifikasi, bukan implementasinya. Saya pribadi mengambil 'spesifikasi' untuk memasukkan semua input (termasuk variabel anggota) dan semua output (termasuk efek samping).
Telastyn
1
Ini hanya satu utas khusus di StackOverflow, tentang kasus tertentu, yang tidak boleh digeneralisasi secara berlebihan. Terutama karena posting saat ini jelas tentang kode pengujian yang sudah ditulis.
Péter Török
1

Negara itu jahat. Fungsi berikut ini tidak memerlukan uji unit karena tidak memiliki efek samping dan dipahami dengan baik apa yang dilakukannya dan apa yang tidak dilakukannya. Mengapa mengujinya? Apakah Anda tidak mempercayai otak Anda sendiri ??? Fungsi statis sangat bagus!

static function bool Foo(bool a, bool b, bool c)
{
    return a && b && c;
}
Pekerjaan
sumber
2
Tidak, saya tidak mempercayai otak saya sendiri - saya belajar cara yang sulit untuk selalu memeriksa ulang apa yang saya lakukan :-) Jadi saya masih akan memerlukan unit test untuk memastikan bahwa saya belum mis misyped apa pun, dan bahwa tidak ada yang akan pergi untuk memecahkan kode di masa depan. Dan lebih banyak tes unit untuk memverifikasi metode pemanggil yang menghitung negara yang diwakili oleh a, bdan c. Anda dapat memindahkan logika bisnis di mana saja Anda inginkan, pada akhirnya Anda masih perlu mengujinya di suatu tempat.
Péter Török
@ Péter Török, Anda juga dapat membuat kesalahan ketik dalam tes dan berakhir dengan positif palsu, jadi di mana Anda berhenti? Apakah Anda menulis unit test untuk unit test Anda? Saya juga tidak mempercayai otak saya 100%, tetapi pada akhirnya menulis kode adalah pekerjaan saya. Dimungkinkan untuk memiliki bug di dalam fungsi ini tetapi penting untuk menulis kode sedemikian rupa sehingga bug akan mudah dilacak ke sumbernya dan sehingga setelah Anda mengisolasi masalah dan telah melakukan perbaikan, Anda lebih baik . Kode yang ditulis dengan baik dapat mengandalkan sebagian besar tes integrasi infoq.com/presentations/Simple-Made-Easy
Job
2
Memang tes juga bisa salah. (TDD mengatasinya dengan membuat tes gagal terlebih dahulu.) Namun, membuat jenis kesalahan yang sama dua kali (dan menghadapinya) memiliki probabilitas yang jauh lebih rendah. Secara umum, tidak ada jumlah dan jenis pengujian yang dapat membuktikan bahwa perangkat lunak bebas bug, cukup kurangi kemungkinan bug ke tingkat yang dapat diterima. Dan dalam kecepatan melacak bug ke sumbernya, IMO tidak ada yang dapat mengalahkan unit test - umpan balik cepat rulez :-)
Péter Török
"Fungsi berikut tidak perlu tes unit" Saya pikir Anda sedang sarkastik di sini, tetapi tidak jelas. Apakah saya percaya otak saya sendiri? TIDAK! Apakah saya mempercayai otak lelaki berikutnya yang menyentuh kode? BAHKAN LEBIH BANYAK TIDAK! Apakah saya percaya bahwa semua asumsi di balik kode akan benar satu tahun dari sekarang? ... Anda mengerti maksud saya. Juga, fungsi statis membunuh OO ... jika Anda ingin melakukan FP, maka gunakan bahasa FP.
Rob
1

Saya tahu pertanyaan ini sudah cukup lama. Tapi saya ingin memberikan perspektif lain untuk masalah ini.

Pertama, unit test Anda harus memiliki dua tujuan:

  1. Buat dokumentasi untuk Anda dan rekan tim Anda, jadi setelah jangka waktu tertentu Anda bisa membaca tes unit dan pastikan Anda mengerti what's the class' intentiondanhow the class is doing its work
  2. Saat berkembang, unit test memastikan kode yang kita tulis sedang melakukan tugasnya seperti yang dimaksudkan dalam pikiran kita.

Jadi, rekapitulasi masalah, kami ingin menguji a complex if statement, untuk contoh yang diberikan, ada 2 ^ 3 kemungkinan, itu adalah jumlah tes penting yang dapat kami tulis.

  • Anda dapat beradaptasi dengan fakta ini dan menuliskan 8 tes atau memanfaatkan tes parametrized
  • Anda juga dapat mengikuti jawaban lain dan ingat bahwa tes harus jelas dengan maksud, dengan cara ini kita tidak akan mengacaukan terlalu banyak detail yang dalam waktu dekat mungkin membuat lebih sulit untuk dipahami what is doing the code

Di sisi lain, jika Anda berada dalam posisi bahwa tes Anda bahkan lebih kompleks daripada implementasi, itu karena implementasinya harus dirancang ulang (kurang lebih tergantung pada kasus) daripada tes itu sendiri.

Untuk pernyataan if kompleks, misalnya, Anda dapat berpikir tentang pola responsabilitas berantai , menerapkan setiap penangan dengan cara ini:

If some simple business rule apply, derive to the next handler

Seberapa sederhana untuk menguji berbagai aturan sederhana, bukan aturan yang kompleks?

Semoga ini bisa membantu,

cnexans
sumber
0

Ini adalah salah satu kasus di mana Sesuatu seperti quickcheck ( http://en.wikipedia.org/wiki/QuickCheck ) akan menjadi teman Anda. Alih-alih menuliskan semua N case dengan tangan, minta komputer membuat semua (atau setidaknya sejumlah besar) kasus uji yang mungkin dan memvalidasi bahwa semua mengembalikan hasil yang masuk akal.

Kami memprogram komputer untuk mencari nafkah di sini, mengapa tidak memprogram komputer untuk membuat test case untuk Anda?

Zachary K
sumber
0

Anda bisa mengubah kondisi menjadi kondisi penjaga:

if (! PassesBusinessRule1) {
    return false;
}

if (! PassesBusinessRule2) {
    return false;
}

if (! PassesBusinessRule3) {
    return false;
}

Saya tidak berpikir itu mengurangi jumlah kasus, tetapi pengalaman saya adalah bahwa lebih mudah untuk memecahkannya dengan cara ini.

(Perhatikan bahwa saya penggemar "titik keluar" yang besar, tetapi saya membuat pengecualian untuk kondisi penjaga. Tetapi ada cara lain untuk menyusun kode sehingga Anda tidak memiliki pengembalian terpisah.)

rampok
sumber