Apakah saya benar-benar membutuhkan kerangka kerja unit test?


19

Saat ini di pekerjaan saya, kami memiliki serangkaian besar unit test untuk aplikasi C ++ kami. Namun kami tidak menggunakan kerangka uji unit. Mereka hanya menggunakan makro C yang pada dasarnya membungkus pernyataan dan cout. Sesuatu seperti:

VERIFY(cond) if (!(cond)) {std::cout << "unit test failed at " << __FILE__ << "," << __LINE__; asserst(false)}

Kemudian kita cukup membuat fungsi untuk masing-masing pengujian seperti

void CheckBehaviorYWhenXHappens()
{
    // a bunch of code to run the test
    //
    VERIFY(blah != blah2);
    // more VERIFY's as needed
}

Server CI kami menerima "uji unit gagal" dan gagal membangun, mengirim email pesan kepada pengembang.

Dan jika kita memiliki kode setup duplikat, kita cukup refactor seperti kita akan kode duplikat lain yang kita miliki dalam produksi. Kami membungkusnya di belakang fungsi pembantu, membuat beberapa kelas tes membungkus skenario yang sering digunakan.

Saya tahu ada kerangka kerja di luar sana seperti CppUnit dan meningkatkan unit test. Saya bertanya-tanya apa nilai yang ditambahkan oleh ini? Apakah saya kehilangan apa yang dibawa ini ke meja? Adakah sesuatu yang berguna yang bisa saya peroleh dari mereka? Saya ragu-ragu untuk menambahkan ketergantungan kecuali itu menambah nilai nyata terutama karena tampaknya apa yang kita miliki adalah sederhana dan bekerja dengan baik.

Jawaban:


8

Seperti yang telah dikatakan orang lain, Anda sudah memiliki kerangka kerja buatan sendiri yang sederhana.

Tampaknya sepele untuk membuatnya. Namun, ada beberapa fitur lain dari kerangka kerja unit-test yang tidak begitu mudah diimplementasikan, karena mereka mengambil beberapa pengetahuan lanjutan tentang bahasa tersebut. Fitur yang biasanya saya butuhkan dari kerangka uji dan tidak begitu mudah untuk homebrew adalah:

  • Pengumpulan otomatis kasus uji. Yaitu mendefinisikan metode pengujian baru harus cukup untuk menjalankannya. JUnit secara otomatis mengumpulkan semua metode yang namanya dimulai dengan test, NUnit memiliki [Test]anotasi, Boost.Test menggunakan BOOST_AUTO_TEST_CASEdan BOOST_FIXTURE_TEST_CASEmakro.

    Ini sebagian besar kemudahan, tetapi setiap sedikit kenyamanan yang Anda dapatkan meningkatkan kemungkinan pengembang benar-benar akan menulis tes yang seharusnya dan mereka akan menghubungkannya dengan benar. Jika Anda memiliki instruksi panjang, seseorang akan kehilangan sebagian dari mereka sekarang dan daripada dan mungkin beberapa tes tidak akan berjalan dan tidak ada yang akan memperhatikan.

  • Kemampuan untuk menjalankan kasus uji yang dipilih, tanpa mengubah kode dan mengkompilasi ulang. Kerangka kerja unit-test yang layak memungkinkan Anda untuk menentukan tes mana yang ingin Anda jalankan pada command-line. Jika Anda ingin men-debug pada unit test (ini poin terpenting bagi mereka untuk banyak pengembang), Anda harus dapat memilih hanya beberapa yang akan dijalankan, tanpa mengubah-ubah kode di semua tempat.

    Katakanlah Anda baru saja menerima laporan bug # 4211 dan dapat direproduksi dengan uji unit. Jadi Anda menulis satu, tetapi daripada Anda harus memberitahu pelari untuk menjalankan tes itu, sehingga Anda dapat men-debug apa yang sebenarnya salah di sana.

  • Kemampuan untuk menandai tes yang diharapkan gagal, per kasus uji, tanpa memodifikasi pemeriksaan itu sendiri. Kami benar-benar mengubah kerangka kerja untuk mendapatkan yang ini.

    Setiap test suite berukuran layak akan memiliki tes, yang gagal karena fitur yang mereka uji belum diimplementasikan, belum selesai, belum ada yang punya waktu untuk memperbaikinya atau sesuatu. Tanpa kemampuan untuk menandai tes sebagai kegagalan yang diharapkan, Anda tidak akan melihat kegagalan lain ketika ada beberapa yang teratur, sehingga tes berhenti melayani tujuan utama mereka.


terima kasih saya pikir ini adalah jawaban terbaik. Saat ini makro saya melakukan tugasnya, tetapi saya tidak dapat melakukan salah satu fitur yang Anda sebutkan.
Doug T.

1
@Jan Hudec "Ini sebagian besar kemudahan, tetapi setiap sedikit kenyamanan yang Anda dapatkan meningkatkan kesempatan pengembang benar-benar akan menulis tes yang seharusnya dan bahwa mereka akan menghubungkannya dengan benar."; Semua kerangka kerja pengujian adalah (1) tidak perlu diinstal, seringkali memiliki lebih banyak instruksi instalasi yang ketinggalan jaman atau tidak lengkap daripada instruksi yang berlaku terkini; (2) jika Anda berkomitmen untuk kerangka kerja pengujian secara langsung, tanpa antarmuka di tengah, Anda sudah menikah dengannya, beralih kerangka kerja tidak selalu mudah.
Dmitry

@Jan Hudec Jika kita mengharapkan lebih banyak orang menulis unit test, kita harus memiliki hasil lebih banyak di google untuk "Apa itu Unit Test", daripada "What is Unit Testing". Tidak ada gunanya melakukan Pengujian Unit jika Anda tidak tahu apa Tes Unit independen dari Kerangka Pengujian Unit atau definisi Pengujian Unit. Anda tidak dapat melakukan Pengujian Unit kecuali Anda memiliki pemahaman yang kuat tentang apa yang dimaksud dengan Uji Unit, karena jika tidak, tidak ada gunanya melakukan Pengujian Unit.
Dmitry

Saya tidak membeli argumen kenyamanan ini. Menulis kode tes sangat sulit jika Anda meninggalkan dunia contoh sepele. Semua ini mockup, setup, pustaka, program server mockup eksternal dll. Mereka semua mengharuskan Anda mengetahui kerangka uji dari dalam ke luar.
Lothar

@Lothar, ya, itu semua banyak pekerjaan dan banyak yang harus dipelajari, tetapi masih harus menulis boilerplate sederhana berulang-ulang karena Anda kekurangan beberapa utilitas berguna membuat pekerjaan jauh lebih tidak menyenangkan dan yang membuat perbedaan efektifitas yang nyata.
Jan Hudec

27

Sepertinya Anda sudah menggunakan kerangka kerja, kerangka buatan sendiri.

Apa nilai tambah dari kerangka kerja yang lebih populer? Saya akan mengatakan bahwa nilai yang mereka tambahkan adalah bahwa ketika Anda harus bertukar kode dengan orang-orang di luar perusahaan Anda, Anda dapat melakukannya, karena ini didasarkan pada kerangka kerja yang dikenal dan digunakan secara luas .

Kerangka buatan rumah, di sisi lain, memaksa Anda untuk tidak pernah membagikan kode Anda, atau untuk menyediakan kerangka kerja itu sendiri, yang mungkin menjadi rumit dengan pertumbuhan kerangka itu sendiri.

Jika Anda memberikan kode kepada kolega apa adanya, tanpa penjelasan dan tanpa kerangka kerja unit test, ia tidak akan dapat menyusunnya.

Kelemahan kedua dari kerangka buatan adalah kompatibilitas . Kerangka kerja pengujian unit populer cenderung memastikan kompatibilitas dengan berbagai IDE, sistem kontrol versi, dll. Untuk saat ini, mungkin tidak terlalu penting bagi Anda, tetapi apa yang akan terjadi jika suatu hari Anda perlu mengubah sesuatu di server CI Anda atau bermigrasi ke IDE baru atau VCS baru? Apakah Anda akan menemukan kembali roda?

Last but not least, kerangka kerja yang lebih besar menyediakan lebih banyak fitur yang mungkin perlu Anda implementasikan dalam kerangka kerja Anda sendiri suatu hari nanti. Assert.AreEqual(expected, actual)tidak selalu cukup. Bagaimana jika Anda perlu:

  • mengukur presisi?

    Assert.AreEqual(3.1415926535897932384626433832795, actual, 25)
    
  • batal tes apakah itu berjalan terlalu lama? Menerapkan batas waktu mungkin tidak mudah bahkan dalam bahasa yang memfasilitasi pemrograman asinkron.

  • menguji metode yang mengharapkan pengecualian dilemparkan?

  • punya kode yang lebih elegan?

    Assert.Verify(a == null);
    

    baik-baik saja, tetapi bukankah lebih ekspresif dari niat Anda untuk menulis baris berikutnya?

    Assert.IsNull(a);
    

"Kerangka kerja" yang kami gunakan semuanya dalam file header yang sangat kecil dan mengikuti semantik penegasan. Jadi saya tidak terlalu khawatir tentang kekurangan yang Anda daftarkan.
Doug T.

4
Saya menganggap menegaskan bagian paling sepele dari kerangka uji. Pelari yang mengumpulkan dan menjalankan kasus uji dan memeriksa hasil adalah bagian penting yang tidak sepele.
Jan Hudec

@ Jan saya tidak cukup ikuti. Pelari saya adalah rutinitas utama yang umum untuk setiap program C ++. Apakah pelari kerangka uji unit melakukan sesuatu yang lebih canggih dan bermanfaat?
Doug T.

1
Kerangka kerja Anda hanya memungkinkan untuk semantik pengujian tegas dan menjalankan dalam metode utama ... sejauh ini. Tunggu saja sampai Anda harus mengelompokkan pernyataan Anda menjadi beberapa skenario, skenario terkait grup bersama-sama berdasarkan data yang diinisialisasi, dll.
James Kingsbery

@ DougT .: Ya, pelari kerangka unit test yang layak melakukan beberapa hal berguna yang lebih canggih. Lihat jawaban lengkap saya.
Jan Hudec

4

Seperti yang orang lain katakan, Anda sudah memiliki kerangka kerja buatan sendiri.

Satu-satunya alasan saya dapat melihat untuk menggunakan beberapa kerangka kerja pengujian lainnya adalah dari sudut pandang "pengetahuan umum" industri. Pengembang baru tidak perlu mempelajari cara buatan sendiri (meskipun, itu terlihat sangat sederhana).

Selain itu, kerangka kerja pengujian lainnya mungkin memiliki lebih banyak fitur yang dapat Anda manfaatkan.


1
Sepakat. Jika Anda tidak mengalami keterbatasan dengan strategi pengujian Anda saat ini, saya melihat sedikit alasan untuk berubah. Kerangka kerja yang baik mungkin akan memberikan kemampuan organisasi dan pelaporan yang lebih baik, tetapi Anda harus membenarkan pekerjaan tambahan yang diperlukan untuk berintegrasi dengan basis kode Anda (termasuk sistem build Anda).
TMN

3

Anda sudah memiliki kerangka kerja meskipun itu sederhana.

Keuntungan utama dari kerangka kerja yang lebih besar seperti yang saya lihat adalah kemampuan untuk memiliki banyak jenis pernyataan yang berbeda (seperti menegaskan kenaikan gaji), urutan logis untuk pengujian unit, dan kemampuan untuk menjalankan hanya sub-set unit test di sebuah waktu. Juga, pola tes xUnit cukup baik untuk diikuti jika Anda bisa - misalnya setUP () dan tearDown () satu. Tentu saja, itu mengunci Anda ke dalam kerangka kerja tersebut. Perhatikan bahwa beberapa kerangka kerja memiliki integrasi tiruan yang lebih baik daripada yang lain - google tiruan dan uji misalnya.

Berapa lama waktu yang Anda butuhkan untuk memperbaiki semua tes unit Anda ke kerangka kerja baru? Berhari-hari atau beberapa minggu mungkin sepadan, tetapi lebih mungkin tidak begitu banyak.


2

Cara saya melihatnya, Anda berdua memiliki keuntungan, dan Anda berada pada "kerugian" (sic).

Keuntungannya adalah Anda memiliki sistem yang membuat Anda nyaman, dan yang berfungsi untuk Anda. Anda senang bahwa itu mengkonfirmasi validitas produk Anda, dan Anda mungkin tidak akan menemukan nilai bisnis dalam mencoba mengubah semua tes Anda untuk sesuatu yang menggunakan kerangka kerja yang berbeda. Jika Anda dapat memperbaiki kode Anda, dan tes Anda mengambil perubahan - atau lebih baik lagi, jika Anda dapat memodifikasi tes Anda dan kode Anda yang ada gagal tes sampai refactored, maka Anda memiliki semua pangkalan Anda tercakup. Namun...

Salah satu keuntungan dari memiliki API pengujian unit yang dirancang dengan baik adalah bahwa ada banyak dukungan asli di sebagian besar IDE modern. Ini tidak akan memengaruhi hard-core VI dan emacs pengguna di luar sana yang mencibir pada pengguna Visual Studio di luar sana, tetapi bagi mereka yang menggunakan yang menggunakan IDE yang baik, Anda memiliki kemampuan untuk men-debug tes Anda dan menjalankannya dalam IDE itu sendiri. Ini bagus, namun ada keuntungan yang lebih besar tergantung pada kerangka yang Anda gunakan, dan itu dalam bahasa yang digunakan untuk menguji kode Anda.

Ketika saya mengatakan bahasa , saya tidak berbicara tentang bahasa pemrograman, tetapi saya berbicara tentang kumpulan kata kaya yang dibungkus dalam sintaks yang fasih yang membuat kode tes dibaca seperti sebuah cerita. Secara khusus, saya telah menjadi advokat untuk penggunaan kerangka kerja BDD . API DotNet BDD favorit pribadi saya adalah StoryQ, tetapi ada beberapa yang lain dengan tujuan dasar yang sama, yaitu untuk mengambil konsep dari dokumen persyaratan, dan menulisnya dalam kode dengan cara yang mirip dengan bagaimana itu ditulis dalam spesifikasi. Namun API yang benar-benar baik melangkah lebih jauh, dengan mencegat setiap pernyataan individu dalam suatu pengujian dan menunjukkan apakah pernyataan itu dijalankan dengan sukses, atau gagal. Ini sangat berguna, karena Anda bisa melihat seluruh tes dieksekusi tanpa kembali lebih awal, yang berarti upaya debug Anda menjadi sangat efisien karena Anda hanya perlu memusatkan perhatian Anda pada bagian-bagian dari tes yang gagal, tanpa perlu men-decode seluruh panggilan urutan. Hal yang menyenangkan lainnya adalah bahwa hasil tes menunjukkan semua informasi ini,

Sebagai contoh dari apa yang saya bicarakan, bandingkan yang berikut ini:

Menggunakan Asserts:

Assert(variable_A == expected_value_1); // if this fails...
Assert(variable_B == expected_value_2); // ...this will not execute
Assert(variable_C == expected_value_3); // ...and nor will this!

Menggunakan API BDD yang lancar: (Bayangkan bahwa bit yang dicetak miring pada dasarnya adalah pointer metode)

WithScenario("Test Scenario")
    .Given(*AConfiguration*) // each method
    .When(*MyMethodToTestIsCalledWith*, variable_A, variable_B, variable_C) // in the
    .Then(*ExpectVariableAEquals*, expected_value_1) // Scenario will
        .And(*ExpectVariableBEquals*, expected_value_2) // indicate if it has
        .And(*ExpectVariableCEquals*, expected_value_3) // passed or failed execution.
    .Execute();

Sekarang diberikan sintaks BDD lebih lama, dan lebih banyak, dan contoh-contoh ini sangat dibuat-buat, namun untuk situasi pengujian yang sangat kompleks di mana banyak hal berubah dalam suatu sistem sebagai akibat dari perilaku sistem yang diberikan, sintaks BDD menawarkan kepada Anda suatu yang jelas deskripsi tentang apa yang Anda uji, dan bagaimana konfigurasi pengujian Anda telah ditentukan, dan Anda dapat menunjukkan kode ini ke non-programmer dan mereka akan langsung mengerti apa yang sedang terjadi. Selain itu, jika "variabel_A" gagal tes dalam kedua kasus, contoh Asserts tidak akan mengeksekusi melewati pernyataan pertama sampai Anda telah memperbaiki masalah, sementara BDD API akan mengeksekusi setiap metode yang disebut dalam rantai, pada gilirannya, dan menunjukkan mana setiap bagian dari pernyataan tersebut salah.

Secara pribadi saya menemukan pendekatan ini bekerja jauh lebih baik daripada kerangka kerja xUnit yang lebih tradisional dalam arti bahwa bahasa pengujian adalah bahasa yang sama dengan pelanggan Anda akan berbicara tentang persyaratan logis mereka. Meski begitu, saya telah berhasil menggunakan kerangka kerja xUnit dengan gaya yang serupa tanpa perlu menemukan API pengujian lengkap untuk mendukung upaya saya, dan sementara pernyataan itu masih akan membuat hubungan arus pendek yang efektif, mereka membaca dengan lebih bersih. Contohnya:

Menggunakan Nunit :

[Test]
void TestMyMethod()
{
    const int theExpectedValue = someValue;

    GivenASetupToTestMyMethod();

    var theActualValue = WhenIExecuteMyMethodToTest();

    Assert.That(theActualValue, Is.EqualTo(theExpectedValue)); // nice, but it's not BDD
}

Jika Anda memutuskan untuk menjelajahi menggunakan API pengujian unit, saran saya adalah untuk bereksperimen dengan sejumlah besar API yang berbeda untuk sementara waktu, dan untuk menjaga dan membuka pikiran tentang pendekatan Anda. Sementara saya pribadi menganjurkan untuk BDD, kebutuhan bisnis Anda sendiri mungkin memerlukan sesuatu yang berbeda untuk keadaan tim Anda. Kuncinya adalah untuk menghindari menebak-nebak sistem yang ada. Anda selalu dapat mendukung tes yang ada dengan beberapa tes menggunakan API lain jika diperlukan, tetapi saya tentu tidak akan merekomendasikan penulisan ulang tes besar hanya untuk membuat semuanya sama. Karena kode lama tidak lagi digunakan, Anda dapat dengan mudah menggantinya dan pengujiannya dengan kode baru, dan pengujian menggunakan API alternatif, dan ini tanpa perlu berinvestasi dalam upaya besar yang tidak selalu memberi Anda nilai bisnis yang nyata. Adapun untuk menggunakan API pengujian unit,


1

Apa yang Anda miliki sederhana dan menyelesaikan pekerjaan. Jika itu berhasil untuk Anda, bagus. Anda tidak perlu kerangka pengujian unit utama, dan saya akan ragu untuk pergi ke pekerjaan porting perpustakaan tes unit yang ada ke kerangka kerja baru. Saya pikir nilai terbesar dari kerangka pengujian unit adalah untuk mengurangi hambatan masuk; Anda baru saja mulai menulis tes, karena kerangka kerja sudah ada. Anda sudah melewati titik itu, jadi Anda tidak akan mendapatkan manfaat itu.

Manfaat lain dari menggunakan kerangka kerja utama - dan ini adalah manfaat kecil, IMO - adalah bahwa pengembang baru mungkin sudah mencapai kecepatan pada kerangka apa pun yang Anda gunakan, dan karenanya akan membutuhkan lebih sedikit pelatihan. Dalam praktiknya, dengan pendekatan langsung seperti yang telah Anda jelaskan, ini seharusnya tidak menjadi masalah besar.

Juga, sebagian besar kerangka kerja utama memiliki fitur tertentu yang mungkin atau mungkin tidak dimiliki kerangka Anda. Fitur-fitur ini mengurangi kode pipa ledeng, dan membuatnya lebih cepat dan lebih mudah untuk menulis kasus uji:

  • Menjalankan uji kasus secara otomatis, dengan menggunakan konvensi penamaan, anotasi / atribut, dll.
  • Berbagai penegasan yang lebih spesifik, sehingga Anda tidak perlu menulis logika kondisional untuk semua pernyataan Anda atau menangkap pengecualian untuk menegaskan tipe mereka.
  • Kategorisasi kasus uji, sehingga Anda dapat dengan mudah menjalankan subsetnya.
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.