Saya memiliki kelas yang saya uji. Kelas memiliki fungsi:apply(List<IRule> rules, List<ITarget> targets);
Dalam satu pengujian, saya ingin memastikan bahwa setiap target telah lulus ke satu aturan, a la:
rule1.AssertWasCalled(fnord => fnord.Test(target1));
rule1.AssertWasCalled(fnord => fnord.Test(target2));
rule1.AssertWasCalled(fnord => fnord.Test(target3));
Tampaknya bagi saya bahwa membatasi diri saya pada pernyataan pernyataan tunggal akan cukup hobgoblin . Apakah saya benar dalam asumsi ini, atau adakah cara lain yang bisa saya nyatakan bahwa setiap target sebenarnya telah diuji?
unit-testing
code-quality
Wayne Werner
sumber
sumber
Jawaban:
Tiga menegaskan pada dasarnya satu tes. Anda menguji perilaku metode pada koleksi, untuk memastikan bahwa setiap item telah menjadi parameter untuk panggilan tertentu (yaitu bahwa setiap item telah diproses dengan benar).
Pengaturan data tiga kali dan dalam tiga metode yang berbeda adalah pemborosan dan kurang dapat dibaca daripada alternatif memiliki beberapa menegaskan.
Pernyataan tunggal "aturan" lebih lanjut tentang membuat pernyataan dari jenis yang berbeda dalam metode yang sama (pada dasarnya menguji hal-hal yang berbeda), yang tidak benar-benar berlaku dalam kasus ini, di mana Anda menguji perilaku tunggal.
sumber
Ini adalah keyakinan saya bahwa pernyataan satu per aturan pengujian ini ada untuk menjaga tes Anda fokus pada satu masalah. Jika Anda menguji 20 hal dalam satu tes, sangat sulit untuk mengetahui apa cakupan Anda. Anda tahu itu menyebabkan masalah ketika Anda tidak dapat memberi nama metode pengujian tanpa kata dan di dalamnya. Misalnya, jika metode pengujian Anda akan lebih akurat disebut
testFooIsTrueAndDbExistsAndBarIsNullAndAnExceptionDoesntOccur()
, Anda mungkin menguji terlalu banyak dalam satu pengujian.Dalam kasus Anda, saya pikir mungkin oke untuk menegaskan tiga kali. Jika Anda ingin membuat kode Anda lebih mudah dibaca, Anda bisa mengekstrak ketiga pernyataan tersebut ke dalam metode yang dinamai
assertWasCalledOnTargets(...)
.sumber
Sebagai contoh khusus Anda, Anda bisa lolos dengan "satu" pernyataan tegas jika Anda melakukan sesuatu seperti:
Itu yang saya lakukan untuk menghindari perasaan bersalah karena memiliki beberapa pernyataan dalam satu tes.
sumber
Saya telah berjuang dengan yang satu ini juga.
Purist (di saya) bersikeras pada satu menegaskan per tes jadi saya akan tahu * persis * di mana semuanya meledak.
Dan kemudian saya menemukan diri saya memotong / menempel banyak kode setup tes yang sama, redundan. Setelah lapisan ketiga atau keempat ini, Anda mulai berkata "Oy! Cukup!"
Kompromi saya adalah menemukan aspek-aspek yang "tidak pernah" pecah. Dan saya akan melapisi potongan-potongan itu bersama-sama dan kemudian menambahkan satu elemen baru yang bisa pecah. Untuk lebih jelasnya, meletakkan beberapa area yang mudah menguap dalam satu pengujian akan menjadi pelanggaran kompromi ini.
sumber
Assume
. Saya baru tahu hari ini.Jika kode pengaturan untuk
target1
berbeda dari kode pengaturan untuktarget2
, jenis pemotongan sudut ini pada akhirnya cenderung menyebabkan kode inisialisasi tes terlalu lama. Ini pada gilirannya adalah kekacauan atau akhirnya menjadi refactored dan digunakan kembali. Jika tes Anda cukup kompleks untuk membenarkan refactoring mereka, tes Anda mungkin menguji lebih dari satu hal.Jika kode pengaturan untuk setiap target pada dasarnya sama, membagi tes Anda menjadi beberapa tes individu mungkin berlebihan.
Jika
target1
dantarget2
merupakan implementasi berbeda dari antarmuka yang sama, Anda seharusnya menambahkan tes unit ke antarmuka (dan memungkinkan kerangka uji Anda untuk menghasilkan tes untuk setiap implementasi antarmuka itu).sumber