Apakah tes Unit dianggap rapuh jika gagal ketika logika bisnis berubah?

27

Silakan lihat kode di bawah ini; itu tes untuk melihat apakah seseorang dengan jenis kelamin perempuan memenuhi syarat untuk menawarkan1:

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id,"Offer1");
    Assert.False(offer1.IsEligible(person));
}

Tes unit ini berhasil. Namun, itu akan gagal jika 'Offer1' ditawarkan kepada wanita di masa depan.

Apakah dapat diterima untuk mengatakan - jika logika bisnis seputar penawaran 1 berubah maka pengujian unit harus berubah. Harap perhatikan bahwa dalam beberapa kasus (untuk beberapa penawaran) logika bisnis diubah dalam database seperti ini:

update Offers set Gender='M' where offer=1;

dan dalam beberapa kasus dalam model domain seperti ini:

if (Gender=Gender.Male)
{
  //do something
}

Harap perhatikan juga bahwa dalam beberapa kasus, logika domain di belakang menawarkan perubahan secara teratur dan dalam beberapa kasus tidak.

w0051977
sumber
2
Pikirkan dari sudut lain: Apakah Anda ingin memiliki tes yang tidak gagal ketika Anda mengubah logika dalam sistem yang diuji?
Fabio

Jawaban:

77

Ini tidak rapuh dalam arti biasa. Tes unit dianggap rapuh jika rusak karena perubahan implementasi yang tidak mempengaruhi perilaku yang diuji. Tetapi jika logika bisnis itu sendiri berubah, maka tes logika ini seharusnya rusak.

Yang mengatakan, jika logika bisnis memang sering berubah, mungkin itu tidak sesuai untuk hardcode harapan ke dalam unit test. Alih-alih, Anda bisa menguji apakah konfigurasi dalam database memengaruhi penawaran seperti yang diharapkan.

Nama tes Returns False When Given A Person With A Gender Of Femaletidak menjelaskan aturan bisnis. Aturan bisnis akan seperti itu Offers Applicable to M should not be applied to persons of gender F.

Jadi, Anda dapat menulis tes yang menegaskan bahwa jika suatu penawaran didefinisikan hanya berlaku untuk orang tipe M, maka orang tipe F tidak akan diindikasikan memenuhi syarat untuk itu. Tes ini akan memastikan logika berfungsi bahkan jika konfigurasi penawaran khusus berubah.

JacquesB
sumber
@ James B, maka itu tidak akan menjadi unit test? atau akankah itu? Saya percaya ini akan menjadi tes integrasi jika database terlibat. Apakah itu benar? Apakah Anda mengatakan jangan menggunakan unit test jika logika bisnis banyak berubah?
w0051977
@ w0051977: Tergantung bagaimana Anda menulis tes. Jika tes termasuk benar-benar mengubah mengubah sesuatu dalam database, maka itu akan menjadi tes integrasi
JacquesB
3
@ w0051977 ide yang lebih baik - tidak memiliki repositori menjadi ketergantungan komponen yang bertanggung jawab untuk menerapkan aturan bisnis. Miliki orkestrasi tingkat tinggi yang memanggil repositori dan kemudian menjalankan aturan bisnis. Sekarang Anda dapat menguji aturan bisnis secara terpisah.
Ant P
5
@ w0051977 tentu saja - tes menentukan perilaku. Jika aturan yang mengatur perilaku perubahan komponen, maka tes harus berubah untuk mencerminkan perubahan perilaku. Yang tidak perlu diubah adalah tes yang menentukan perilaku selain dari apa yang berubah. Jika perilaku ditentukan oleh database, maka tes yang mencakup beberapa kode lain secara inheren tidak terkait dan tidak perlu diubah kecuali jika logika database tersebut berada dalam lingkup tes. Cakupan itu untuk Anda tentukan dan semantik apakah itu tes unit atau tes integrasi tidak terlalu penting.
Ant P
3
@ w0051977 sedikit memperluas gagasan ini, jika logika bisnis berubah atau bug diperbaiki dan tes tidak perlu disesuaikan, itu adalah tanda bahwa tes tidak mencakup kasus yang cukup dan umumnya harus diperluas.
Morgen
14

Ketika properti didefinisikan dalam database produksi (atau klon untuk pengujian), ini bukan tes unit . Tes unit memeriksa unit kerja dan tidak memerlukan kondisi eksternal tertentu untuk bekerja. Ini mengasumsikan yang Offer1didefinisikan dalam database sebagai penawaran khusus pria. Itu keadaan eksternal. Jadi ini lebih merupakan tes integrasi , khususnya tes sistem atau penerimaan . Perhatikan bahwa tes penerimaan seringkali tidak ditulis (tidak dijalankan dalam kerangka uji coba tetapi dilakukan secara manual oleh manusia).

Ketika properti didefinisikan dalam model domain dengan ifpernyataan, tes yang sama adalah tes unit. Dan itu mungkin rapuh. Tetapi masalah sebenarnya adalah bahwa kode tersebut rapuh. Sebagai aturan umum, kode Anda akan lebih tangguh jika perilaku bisnis dapat dikonfigurasi daripada kode keras. Karena penyebaran terburu-buru untuk memperbaiki kesalahan pengkodean kecil harus jarang terjadi. Tetapi persyaratan bisnis yang berubah tanpa pemberitahuan hanyalah hari Selasa (sesuatu yang terjadi setiap minggu).

Anda mungkin menggunakan kerangka kerja unit test untuk menjalankan tes. Tetapi kerangka kerja unit test tidak terbatas pada menjalankan unit test. Mereka dapat dan melakukan tes integrasi juga.

Jika Anda menulis unit test, Anda akan membuat keduanya persondan offer1dari bawah ke atas tanpa bergantung pada status basis data. Sesuatu seperti

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
    offer1.markLimitedToGender("M");

    Assert.False(offer1.IsEligible(person));
}

Perhatikan bahwa ini tidak berubah berdasarkan pada logika bisnis. Ini tidak menyatakan bahwa offer1menolak perempuan. Itu membuat offer1jenis penawaran yang menolak perempuan.

Anda dapat membuat dan mengkonfigurasi database sebagai bagian dari pengujian. Dalam C #, menggunakan NUnit, atau di JUnit Java, Anda akan mengatur database dalam suatu Setupmetode. Agaknya kerangka pengujian Anda memiliki gagasan serupa. Dalam metode itu, Anda bisa memasukkan catatan ke dalam database dengan SQL.

Jika sulit bagi Anda untuk menulis kode yang menggantikan database uji untuk database produksi, itu terdengar seperti kelemahan pengujian dalam aplikasi Anda. Untuk pengujian, akan lebih baik menggunakan sesuatu seperti injeksi ketergantungan yang memungkinkan untuk diganti. Kemudian Anda dapat menulis tes yang independen terhadap aturan bisnis saat ini.

Keuntungan sampingan dari hal ini adalah sering kali lebih mudah bagi pemilik bisnis (tidak harus pemilik perusahaan, lebih seperti orang yang bertanggung jawab atas produk ini dalam hierarki perusahaan) untuk mengonfigurasi aturan bisnis secara langsung. Karena jika Anda memiliki kerangka kerja teknis seperti ini, mudah bagi pemilik bisnis untuk menggunakan antarmuka pengguna (UI) untuk mengonfigurasi penawaran. Pemilik bisnis akan memilih batasan di UI, dan itu akan mengeluarkan markLimitedToGender("M")panggilan. Kemudian ketika tawaran tersebut tetap ada di basis data, ia akan menyimpan ini. Tetapi Anda tidak perlu menyimpan penawaran untuk menggunakannya. Sehingga pengujian Anda dapat membuat dan mengonfigurasi tawaran yang tidak ada di database.

Dalam sistem Anda seperti yang dijelaskan, pemilik bisnis harus mengajukan permintaan ke grup teknis, yang akan mengeluarkan SQL yang sesuai dan memperbarui tes. Atau grup teknis harus mengedit kode dan tes Anda (atau tes kemudian kode). Itu tampaknya pendekatan yang agak berat. Kamu bisa melakukannya. Tetapi perangkat lunak Anda (bukan hanya pengujian Anda) akan kurang rapuh jika Anda tidak harus melakukannya.

TL; DR : Anda dapat menulis tes seperti ini, tetapi Anda mungkin lebih baik menulis perangkat lunak sehingga Anda tidak perlu melakukannya.

mdfst13
sumber
Saya alat kebebasan untuk meningkatkan beberapa detail kecil dalam jawaban Anda. Silakan periksa apakah maksud saya benar.
Doc Brown
Tidak ada indikasi dalam posting asli bahwa database terlibat. Jadi mengklaim bahwa ia menganggap bahwa Offer1 sudah ada dalam database adalah aneh.
Winston Ewert
2
@ WinstonEwert: ada indikasi yang jelas, Anda harus membaca pertanyaan lebih hati-hati. Saya tidak menyadarinya pada bacaan pertama, juga, tetapi memang itulah yang dibicarakan OP.
Doc Brown
@ mdfst13, maaf saya melewatkannya. Namun, apa yang OP katakan adalah bahwa kondisinya kadang-kadang dalam database dan kadang-kadang dalam model domain. Jawaban Anda baik-baik saja untuk kasus pertama, dan tidak sopan di yang kedua. Jika Anda akan mengedit jawaban Anda untuk menjelaskan hal itu, saya akan menghapus downvote saya yang tergesa-gesa.
Winston Ewert