Jadi, saya punya modul otentikasi yang saya tulis beberapa waktu lalu. Sekarang saya melihat kesalahan cara saya dan menulis tes unit untuk itu. Saat menulis unit test, saya kesulitan menemukan nama baik dan area bagus untuk diuji. Misalnya, saya punya hal-hal seperti
- MembutuhkanLogin_should_redirect_when_not_logged_in
- MembutuhkanLogin_should_pass_through_when_logged_in
- Login_should_work_when_given_proper_credentials
Secara pribadi, saya pikir itu agak jelek, meskipun sepertinya "tepat". Saya juga mengalami kesulitan membedakan antara tes hanya dengan memindai mereka (saya harus membaca nama metode setidaknya dua kali untuk mengetahui apa yang baru saja gagal)
Jadi, saya berpikir bahwa mungkin alih-alih menulis tes yang murni menguji fungsionalitas, mungkin menulis serangkaian tes yang mencakup skenario.
Misalnya, ini adalah rintisan tes yang saya buat:
public class Authentication_Bill
{
public void Bill_has_no_account()
{ //assert username "bill" not in UserStore
}
public void Bill_attempts_to_post_comment_but_is_redirected_to_login()
{ //Calls RequiredLogin and should redirect to login page
}
public void Bill_creates_account()
{ //pretend the login page doubled as registration and he made an account. Add the account here
}
public void Bill_logs_in_with_new_account()
{ //Login("bill", "password"). Assert not redirected to login page
}
public void Bill_can_now_post_comment()
{ //Calls RequiredLogin, but should not kill request or redirect to login page
}
}
Apakah ini pola yang terdengar? Saya telah melihat kisah penerimaan dan semacamnya, tetapi ini pada dasarnya berbeda. Perbedaan besar adalah bahwa saya datang dengan skenario untuk "memaksa" tes. Daripada mencoba secara manual untuk menemukan kemungkinan interaksi yang perlu saya uji. Juga, saya tahu ini mendorong unit test yang tidak menguji persis satu metode dan kelas. Saya pikir ini tidak masalah. Juga, saya sadar bahwa ini akan menyebabkan masalah untuk setidaknya beberapa kerangka kerja pengujian, karena mereka biasanya menganggap bahwa pengujian independen satu sama lain dan urutan tidak masalah (di mana dalam kasus ini).
Ngomong-ngomong, apakah ini pola yang disarankan? Atau, apakah ini akan sangat cocok untuk tes integrasi API saya daripada sebagai tes "unit"? Ini hanya dalam proyek pribadi, jadi saya terbuka untuk eksperimen yang mungkin atau mungkin tidak berjalan dengan baik.
_test
menambahkan dan menggunakan komentar untuk mencatat hasil apa yang saya harapkan. Jika ini adalah proyek pribadi, temukan beberapa gaya yang Anda rasa nyaman dan pertahankan.Jawaban:
Ya, sebaiknya berikan nama pengujian Anda pada contoh skenario yang Anda uji. Dan menggunakan alat pengujian unit Anda untuk lebih dari sekedar pengujian unit mungkin ok juga, banyak orang melakukan ini dengan sukses (saya juga).
Tapi tidak, itu jelas bukan ide yang baik untuk menulis tes Anda dengan cara di mana urutan pelaksanaan tes itu penting. Misalnya, NUnit memungkinkan pengguna untuk memilih secara interaktif tes mana yang ingin dieksekusi, jadi ini tidak akan berfungsi seperti yang dimaksudkan lagi.
Anda dapat menghindari ini dengan mudah di sini dengan memisahkan bagian pengujian utama dari setiap pengujian (termasuk "menegaskan") dari bagian-bagian yang mengatur sistem Anda dalam keadaan awal yang benar. Menggunakan contoh Anda di atas: tulis metode untuk membuat akun, masuk dan kirim komentar - tanpa ada pernyataan. Kemudian gunakan kembali metode tersebut dalam tes yang berbeda. Anda juga harus menambahkan beberapa kode ke
[Setup]
metode perlengkapan pengujian Anda untuk memastikan sistem dalam keadaan awal yang didefinisikan dengan benar (misalnya, tidak ada akun sejauh ini dalam database, tidak ada yang terhubung sejauh ini dll).EDIT: Tentu saja, ini tampaknya bertentangan dengan sifat "cerita" dari tes Anda, tetapi jika Anda memberikan metode yang berarti pada helper Anda, Anda menemukan cerita Anda dalam setiap tes.
Jadi, akan terlihat seperti ini:
sumber
Masalah dengan menceritakan sebuah cerita dengan tes unit adalah bahwa tidak membuat eksplisit bahwa tes unit harus diatur dan dijalankan sepenuhnya secara independen satu sama lain.
Tes unit yang baik harus sepenuhnya diisolasi dari semua kode dependen lainnya, ini adalah unit kode terkecil yang dapat diuji.
Ini memberikan manfaat yang sama halnya dengan mengkonfirmasi kode bekerja, jika tes gagal Anda mendapatkan diagnosis di mana kode salah secara gratis. Jika suatu tes tidak terisolasi, Anda harus melihat pada apa itu tergantung untuk mencari tahu apa yang salah dan kehilangan manfaat utama dari pengujian unit. Memiliki urutan masalah eksekusi juga dapat meningkatkan banyak negatif palsu, jika tes gagal, mungkin tes berikut gagal meskipun kode yang mereka uji berfungsi dengan baik.
Artikel bagus yang lebih mendalam adalah klasik tentang tes hybrid kotor .
Untuk membuat kelas, metode, dan hasil dapat dibaca, pengujian Seni Unit yang hebat menggunakan konvensi penamaan
Kelas Tes:
Metode tes:
Untuk menyalin contoh @Doc Brown, daripada menggunakan [Setup] yang berjalan sebelum setiap tes, saya menulis metode pembantu untuk membangun objek terisolasi untuk menguji.
Jadi tes gagal memiliki nama yang bermakna yang memberi Anda beberapa narasi tentang metode apa yang gagal, kondisi dan hasil yang diharapkan.
Begitulah cara saya selalu menulis unit test, tetapi seorang teman telah banyak sukses dengan Gerkin .
sumber
Apa yang Anda gambarkan terdengar lebih seperti Behavior Driven Design (BDD) daripada pengujian unit kepada saya. Lihatlah SpecFlow yang merupakan teknologi .NET BDD yang didasarkan pada Gherkin DSL.
Hal-hal kuat yang dapat dibaca / ditulis manusia mana pun tanpa mengetahui apa pun tentang pengkodean. Tim uji kami menikmati kesuksesan besar memanfaatkannya untuk suite uji integrasi kami.
Mengenai konvensi untuk unit test, jawaban @ DocBrown tampaknya solid.
sumber
assert(value === expected)
BDD =value.should.equals(expected)
+ Anda menggambarkan fitur dalam lapisan yang memecahkan masalah "unit test independent". Ini gaya yang hebat!