Memisahkan unit tes dengan persyaratan atau metode


16

Pertama, minta maaf untuk judulnya, saya tidak bisa memikirkan cara termudah untuk menjelaskannya!

Saya memiliki metode yang saya ingin menulis unit test. Saya akan menjaganya tetap generik karena saya tidak ingin membahas implementasi metode ini, hanya pengujian saja. Metodenya adalah:

public void HandleItem(item a)
{         
     CreateNewItem();
     UpdateStatusOnPreviousItem();
     SetNextRunDate();
}

Jadi kelas ini memiliki satu metode publik yang kemudian memanggil beberapa metode pribadi untuk melakukan logika.

Jadi ketika menulis unit test saya ingin memeriksa ketiga hal yang telah dilakukan. Karena mereka semua dipanggil dengan cara yang sama, saya pikir saya bisa melakukannya sebagai satu tes:

public void GivenItem_WhenRun_Thenxxxxx
{
     HandleItem(item);
     // Assert item has been created
     // Assert status has been set on the previous item
     // Assert run date has been set
}

Tapi saya pikir saya juga bisa menulisnya sebagai tiga tes terpisah:

public void GivenItem_WhenRun_ThenItemIsCreated()
{
    HandleItem(item);
}

public void GivenItem_WhenRun_ThenStatusIsUpdatedOnPreviousItem()
{
   HandleItem(item);
}

public void GivenItem_WhenRun_ThenRunDateIsSet()
{
     HandleItem(item);
}

Jadi bagi saya ini tampak lebih baik karena pada dasarnya daftar persyaratan, tetapi kemudian ketiganya terkait dan memang membutuhkan pekerjaan yang sama persis dilakukan pada metode yang diuji, jadi saya menjalankan kode yang sama 3 kali.

Apakah ada pendekatan yang disarankan untuk dilakukan?

Terima kasih

Jawaban:


29

Ada perbedaan tipis antara kedua pendekatan. Dalam kasus pertama, saat pertamaAssert gagal, dua lainnya tidak berjalan lagi. Dalam kasus kedua, ketiga tes selalu dijalankan, meskipun satu gagal. Bergantung pada sifat fungsionalitas yang diuji, ini mungkin cocok atau tidak cocok dengan kasus Anda:

  • jika masuk akal untuk menjalankan tiga pernyataan secara independen dari yang lain, karena ketika satu gagal, dua lainnya mungkin masih tidak gagal, maka pendekatan kedua memiliki keuntungan Anda mendapatkan hasil tes penuh untuk semua 3 tes dalam satu kali. Ini bisa bermanfaat jika Anda memiliki waktu pengembangan yang nyata, karena ini memberi Anda kesempatan untuk memperbaiki hingga 3 kesalahan sekaligus sebelum melakukan pembangunan berikutnya.

  • Namun, jika kegagalan dari tes pertama akan selalu menyiratkan dua tes lainnya juga akan gagal, maka mungkin lebih baik menggunakan pendekatan pertama (karena tidak masuk akal untuk menjalankan tes jika Anda sudah tahu sebelumnya itu akan gagal).


2
+1, poin bagus. Tidak terpikir oleh saya bahwa waktu build juga bisa menjadi hambatan.
Kilian Foth

1
@KilianFoth: Anda tidak cukup sering bekerja di C ++ :(
Matthieu M.

1
@MatthieuM .: agar adil, pertanyaannya ditandai "C #"
Doc Brown

10

Jawaban singkat: Jauh lebih penting bahwa tes Anda mencakup semua fungsi daripada bagaimana mereka melakukannya.

Jawaban yang lebih panjang: Jika Anda masih ingin memilih di antara solusi yang sebagian besar setara ini, Anda dapat menggunakan kriteria tambahan untuk apa yang terbaik. Contohnya,

  • readibility: jika metode melakukan banyak hal yang tidak terkait erat, tes gabungan mungkin sulit dimengerti. Namun, metode itu sendiri mungkin juga sulit untuk dipahami, jadi mungkin Anda harus memperbaiki metode tersebut daripada tes!)
  • efisiensi: jika menjalankan metode ini membutuhkan waktu lama, itu mungkin menjadi alasan yang lemah untuk menggabungkan ketiga pemeriksaan untuk menghemat waktu
  • efficiency2: jika menjalankan kode pengaturan kerangka kerja Anda membutuhkan waktu lama, itu juga bisa menjadi alasan yang lemah untuk menghindari beberapa metode pengujian. (Namun, jika ini benar-benar masalah, Anda mungkin harus memperbaiki atau mengubah pengaturan pengujian Anda - tes regresi kehilangan banyak nilainya jika Anda tidak dapat menjalankannya secepat kilat.)

2

Gunakan satu panggilan metode dengan beberapa menegaskan. Inilah alasannya:

Ketika Anda menguji HandleItem (a), Anda menguji bahwa metode telah membawa item ke status yang benar. Alih-alih "satu menegaskan per tes", pikirkan "satu konsep logis per tes".

Pertanyaan: Jika CreateNewItem gagal, tetapi dua metode lainnya berhasil, apakah ini berarti bahwa HandleItem berhasil diselesaikan? Saya kira tidak.

Dengan beberapa penegasan (dengan pesan yang sesuai) Anda akan tahu persis apa yang gagal. Anda biasanya menguji metode beberapa kali untuk beberapa input atau status input, bukan untuk menghindari beberapa pernyataan.

IMO, pertanyaan-pertanyaan ini biasanya merupakan pertanda dari sesuatu yang lain. Ini pertanda bahwa HandleItem bukanlah sesuatu yang dapat Anda "uji unit" karena tampaknya hanya mendelegasikan ke metode lain. Ketika Anda hanya memvalidasi bahwa HandleItem memanggil metode lain dengan benar, itu menjadi lebih dari kandidat uji integrasi (dalam hal ini Anda masih memiliki 3 menegaskan).

Anda mungkin ingin mempertimbangkan untuk membuat 3 metode lainnya publik dan mengujinya secara mandiri. Atau bahkan mengekstraksi mereka ke kelas lain.


0

Gunakan pendekatan ke-2. Dengan pendekatan pertama Anda, jika tes gagal, Anda tidak akan langsung tahu mengapa, karena itu bisa menjadi salah satu dari 3 fungsi yang gagal. Dengan pendekatan kedua Anda akan langsung tahu di mana masalah terjadi. Anda dapat memasukkan kode duplikat ke dalam fungsi Pengaturan Tes Anda.


-1

IMHO Anda harus menguji tiga bagian dari metode ini secara terpisah sehingga Anda tahu lebih spesifik di mana ada masalah ketika mereka lakukan sambil menghindari pergi ke bagian yang sama dari kode Anda dua kali.


-2

Saya tidak berpikir ada alasan kuat untuk menulis metode pengujian terpisah untuk use case Anda. Jika Anda ingin mendapatkan hasil dari ketiga kondisi variabel, Anda dapat menguji ketiganya dan mencetak kegagalannya dengan menggabungkannya dalam a stringdan menyatakan apakah string masih kosong setelah Anda menyelesaikan tes. Dengan menyimpan semuanya dalam metode yang sama, kondisi dan pesan kegagalan Anda mendokumentasikan kondisi pasca-metode yang diharapkan di satu tempat, daripada membaginya menjadi tiga metode yang mungkin terpisah nanti.

Ini berarti bahwa tes tunggal Anda akan memiliki lebih banyak kode, tetapi jika Anda memiliki begitu banyak kondisi pasca yang merupakan masalah, Anda mungkin ingin memperbaiki metode pengujian Anda untuk menguji masing-masing metode di dalamnya HandleItem.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.