Sejauh ini saya menghindari mimpi buruk yang menguji kode multi-threaded karena sepertinya terlalu banyak ladang ranjau. Saya ingin bertanya bagaimana orang telah pergi tentang pengujian kode yang bergantung pada utas untuk eksekusi yang sukses, atau hanya bagaimana orang pergi tentang menguji jenis-jenis masalah yang hanya muncul ketika dua utas berinteraksi dengan cara tertentu?
Ini sepertinya masalah yang sangat penting bagi programmer saat ini, akan sangat berguna untuk menyatukan pengetahuan kita tentang imho yang satu ini.
Jawaban:
Dengar, tidak ada cara mudah untuk melakukan ini. Saya sedang mengerjakan proyek yang inheren multithreaded. Acara datang dari sistem operasi dan saya harus memprosesnya secara bersamaan.
Cara paling sederhana untuk menangani pengujian kode aplikasi multithreaded yang kompleks adalah: Jika terlalu rumit untuk diuji, Anda salah melakukannya. Jika Anda memiliki satu instance yang memiliki beberapa utas yang bertindak atasnya, dan Anda tidak dapat menguji situasi di mana utas ini saling bertindihan, maka desain Anda harus diulang. Baik sesederhana dan serumit ini.
Ada banyak cara untuk memprogram untuk multithreading yang menghindari utas berjalan melalui instance secara bersamaan. Yang paling sederhana adalah membuat semua benda Anda tidak berubah. Tentu saja, itu biasanya tidak mungkin. Jadi, Anda harus mengidentifikasi tempat-tempat di desain Anda di mana utas berinteraksi dengan contoh yang sama dan mengurangi jumlah tempat-tempat itu. Dengan melakukan ini, Anda mengisolasi beberapa kelas di mana multithreading benar-benar terjadi, mengurangi kompleksitas keseluruhan pengujian sistem Anda.
Tetapi Anda harus menyadari bahwa bahkan dengan melakukan ini Anda masih tidak dapat menguji setiap situasi di mana dua utas saling menginjak. Untuk melakukan itu, Anda harus menjalankan dua utas secara bersamaan dalam pengujian yang sama, kemudian mengontrol dengan tepat garis apa yang mereka jalankan pada saat tertentu. Yang terbaik yang dapat Anda lakukan adalah mensimulasikan situasi ini. Tetapi ini mungkin mengharuskan Anda untuk kode khusus untuk pengujian, dan itu hanya setengah langkah menuju solusi yang benar.
Mungkin cara terbaik untuk menguji kode untuk masalah threading adalah melalui analisis statis kode. Jika kode berulir Anda tidak mengikuti serangkaian pola aman utas yang terbatas, maka Anda mungkin memiliki masalah. Saya percaya Analisis Kode dalam VS memang mengandung beberapa pengetahuan tentang threading, tapi mungkin tidak banyak.
Lihatlah, saat ini keadaan sedang berlangsung (dan mungkin akan menjadi waktu yang tepat untuk datang), cara terbaik untuk menguji aplikasi multithreaded adalah mengurangi kompleksitas kode ulir sebanyak mungkin. Minimalkan area di mana utas berinteraksi, ujilah sebaik mungkin, dan gunakan analisis kode untuk mengidentifikasi area berbahaya.
sumber
Sudah lama ketika pertanyaan ini diposting, tetapi masih belum dijawab ...
Jawaban kleolb02 adalah jawaban yang bagus. Saya akan mencoba masuk ke detail lebih lanjut.
Ada cara, yang saya praktekkan untuk kode C #. Untuk pengujian unit, Anda harus dapat memprogram tes yang dapat direproduksi , yang merupakan tantangan terbesar dalam kode multithreaded. Jadi jawaban saya bertujuan memaksakan kode asinkron ke dalam test harness, yang bekerja secara serempak .
Ini adalah ide dari buku Gerard Meszardos " xUnit Test Patterns " dan disebut "Humble Object" (hlm. 695): Anda harus memisahkan kode logika inti dan apa pun yang berbau seperti kode asinkron satu sama lain. Ini akan menghasilkan kelas untuk logika inti, yang bekerja secara serempak .
Ini menempatkan Anda pada posisi untuk menguji kode logika inti secara sinkron . Anda memiliki kontrol mutlak atas waktu panggilan yang Anda lakukan pada logika inti dan dengan demikian dapat melakukan tes yang dapat direproduksi . Dan ini adalah keuntungan Anda dari memisahkan logika inti dan logika asinkron.
Logika inti ini perlu dibungkus oleh kelas lain, yang bertanggung jawab untuk menerima panggilan ke logika inti secara serempak dan mendelegasikan panggilan-panggilan ini ke logika inti. Kode produksi hanya akan mengakses logika inti melalui kelas itu. Karena kelas ini seharusnya hanya mendelegasikan panggilan, ini adalah kelas yang sangat "bodoh" tanpa banyak logika. Jadi, Anda dapat menjaga tes unit Anda untuk kelas pekerja asikronus ini minimal.
Apa pun di atas itu (menguji interaksi antar kelas) adalah tes komponen. Juga dalam kasus ini, Anda harus dapat memiliki kontrol mutlak atas waktu, jika Anda tetap berpegang pada pola "Objek Humble".
sumber
Memang tangguh! Dalam pengujian unit (C ++) saya, saya memecahnya menjadi beberapa kategori di sepanjang garis pola konkurensi yang digunakan:
Tes unit untuk kelas yang beroperasi dalam satu utas dan tidak menyadari - mudah, tes seperti biasa.
Tes unit untuk objek Monitor (yang menjalankan metode yang disinkronkan di utas kontrol penelepon) yang mengekspos API publik yang disinkronkan - instantiate beberapa utas tiruan yang menggunakan API. Buat skenario yang menggunakan kondisi internal objek pasif. Termasuk satu tes lagi yang pada dasarnya mengalahkan heck keluar dari banyak utas untuk jangka waktu yang lama. Ini tidak ilmiah saya tahu tetapi itu membangun kepercayaan diri.
Tes unit untuk objek Aktif (yang merangkum utas atau utas kontrol sendiri) - mirip dengan # 2 di atas dengan variasi tergantung pada desain kelas. API publik dapat memblokir atau non-memblokir, penelepon dapat memperoleh masa depan, data dapat tiba di antrian atau perlu dequeued. Ada banyak kombinasi yang mungkin di sini; kotak putih. Masih membutuhkan beberapa utas tiruan untuk melakukan panggilan ke objek yang sedang diuji.
Sebagai tambahan:
Dalam pelatihan pengembang internal yang saya lakukan, saya mengajarkan Pillars of Concurrency dan dua pola ini sebagai kerangka kerja utama untuk memikirkan dan menguraikan masalah concurrency. Jelas ada konsep yang lebih maju di luar sana tetapi saya telah menemukan bahwa serangkaian dasar ini membantu menjaga insinyur keluar dari sup. Ini juga mengarah pada kode yang lebih dapat diuji unit, seperti dijelaskan di atas.
sumber
Saya telah menghadapi masalah ini beberapa kali dalam beberapa tahun terakhir ketika menulis kode penanganan utas untuk beberapa proyek. Saya memberikan jawaban terlambat karena sebagian besar jawaban lainnya, sambil memberikan alternatif, sebenarnya tidak menjawab pertanyaan tentang pengujian. Jawaban saya ditujukan kepada kasus-kasus di mana tidak ada alternatif untuk kode multithreaded; Saya membahas masalah desain kode untuk kelengkapan, tetapi juga membahas pengujian unit.
Menulis kode multithread yang dapat diuji
Hal pertama yang harus dilakukan adalah memisahkan kode penanganan utas produksi Anda dari semua kode yang melakukan pemrosesan data aktual. Dengan begitu, pemrosesan data dapat diuji sebagai kode ulir tunggal, dan satu-satunya yang dilakukan kode multithread adalah mengoordinasikan utas.
Hal kedua yang perlu diingat adalah bahwa bug dalam kode multithread adalah probabilistik; bug yang paling sering memanifestasikan dirinya adalah bug yang akan menyelinap masuk ke dalam produksi, akan sulit untuk mereproduksi bahkan dalam produksi, dan dengan demikian akan menyebabkan masalah terbesar. Untuk alasan ini, pendekatan pengkodean standar penulisan kode dengan cepat dan kemudian debugging sampai berfungsi adalah ide yang buruk untuk kode multithreaded; itu akan menghasilkan kode di mana bug mudah diperbaiki dan bug berbahaya masih ada.
Sebaliknya, ketika menulis kode multithread, Anda harus menulis kode dengan sikap bahwa Anda akan menghindari penulisan bug di tempat pertama. Jika Anda telah menghapus kode pemrosesan data dengan benar, kode penanganan ulir harus cukup kecil - lebih disukai beberapa baris, paling buruk beberapa lusin baris - sehingga Anda memiliki kesempatan untuk menulisnya tanpa menulis bug, dan tentunya tanpa menulis banyak bug , jika Anda memahami threading, luangkan waktu Anda, dan berhati-hatilah.
Unit tes menulis untuk kode multithreaded
Setelah kode multithreaded ditulis selengkap mungkin, masih ada baiknya menulis tes untuk kode tersebut. Tujuan utama dari tes ini bukan untuk menguji bug kondisi ras yang sangat tergantung waktu - tidak mungkin untuk menguji kondisi ras seperti itu berulang - tetapi untuk menguji bahwa strategi penguncian Anda untuk mencegah bug seperti itu memungkinkan beberapa thread untuk berinteraksi sebagaimana dimaksud .
Untuk menguji perilaku penguncian yang benar dengan benar, tes harus memulai beberapa utas. Untuk membuat tes berulang, kami ingin interaksi antara utas terjadi dalam urutan yang dapat diprediksi. Kami tidak ingin menyinkronkan utas secara eksternal dalam pengujian, karena itu akan menutupi bug yang dapat terjadi dalam produksi di mana utas tidak disinkronkan secara eksternal. Itu meninggalkan penggunaan penundaan waktu untuk sinkronisasi utas, yang merupakan teknik yang telah saya gunakan dengan sukses setiap kali saya harus menulis tes kode multithread.
Jika penundaan terlalu pendek, maka pengujian menjadi rapuh, karena perbedaan waktu kecil - katakanlah antara mesin yang berbeda di mana tes dapat dijalankan - dapat menyebabkan waktu dimatikan dan tes gagal. Apa yang biasanya saya lakukan adalah mulai dengan penundaan yang menyebabkan kegagalan pengujian, tingkatkan penundaan sehingga pengujian dapat diandalkan pada mesin pengembangan saya, dan kemudian gandakan penundaan di luar itu sehingga pengujian memiliki peluang bagus untuk melewati mesin lain. Ini berarti bahwa pengujian akan memakan waktu makroskopis, meskipun menurut pengalaman saya, desain pengujian yang cermat dapat membatasi waktu itu tidak lebih dari selusin detik. Karena Anda seharusnya tidak memiliki banyak tempat yang membutuhkan kode koordinasi utas dalam aplikasi Anda, itu seharusnya dapat diterima untuk test suite Anda.
Akhirnya, catat jumlah bug yang ditangkap oleh pengujian Anda. Jika pengujian Anda memiliki cakupan kode 80%, maka diharapkan dapat menangkap sekitar 80% bug Anda. Jika pengujian Anda dirancang dengan baik tetapi tidak menemukan bug, ada kemungkinan Anda tidak memiliki bug tambahan yang hanya akan muncul dalam produksi. Jika tes menangkap satu atau dua bug, Anda mungkin masih beruntung. Di luar itu, dan Anda mungkin ingin mempertimbangkan peninjauan yang cermat atau bahkan penulisan ulang lengkap kode penanganan utas Anda, karena kemungkinan kode tersebut masih mengandung bug tersembunyi yang akan sangat sulit ditemukan hingga kode tersebut diproduksi, dan sangat sulit untuk diperbaiki.
sumber
Saya juga memiliki masalah serius dalam menguji kode multi-threaded. Kemudian saya menemukan solusi yang sangat keren di "Pola Tes xUnit" oleh Gerard Meszaros. Pola yang ia gambarkan disebut objek Humble .
Pada dasarnya ini menjelaskan bagaimana Anda dapat mengekstrak logika menjadi komponen terpisah yang mudah diuji yang dipisahkan dari lingkungannya. Setelah Anda menguji logika ini, Anda dapat menguji perilaku yang rumit (multi-threading, eksekusi asinkron, dll ...)
sumber
Ada beberapa alat di sekitar yang cukup bagus. Berikut ini adalah ringkasan dari beberapa yang Java.
Beberapa alat analisis statis yang baik termasuk FindBugs (memberikan beberapa petunjuk bermanfaat), JLint , Java Pathfinder (JPF & JPF2), dan Bogor .
MultithreadedTC adalah alat analisis dinamis yang cukup baik (terintegrasi ke dalam JUnit) di mana Anda harus menyiapkan kotak uji sendiri.
ConTest dari IBM Research menarik. Itu instrumen kode Anda dengan memasukkan semua jenis perilaku pengubah utas (misalnya tidur & hasil) untuk mencoba mengungkap bug secara acak.
SPIN adalah alat yang sangat keren untuk memodelkan komponen Java Anda (dan lainnya), tetapi Anda perlu memiliki beberapa kerangka kerja yang bermanfaat. Sulit untuk digunakan apa adanya, tetapi sangat kuat jika Anda tahu cara menggunakannya. Cukup banyak alat yang menggunakan SPIN di bawah tenda.
MultithreadedTC mungkin yang paling utama, tetapi beberapa alat analisis statis yang tercantum di atas pasti pantas untuk dilihat.
sumber
Keramahtamahan juga dapat berguna untuk membantu Anda menulis tes unit deterministik. Ini memungkinkan Anda untuk menunggu sampai beberapa negara bagian di sistem Anda diperbarui. Sebagai contoh:
atau
Ini juga memiliki dukungan Scala dan Groovy.
sumber
Cara lain untuk (agak) menguji kode ulir, dan sistem yang sangat kompleks pada umumnya adalah melalui Pengujian Fuzz . Ini tidak bagus, dan tidak akan menemukan segalanya, tetapi kemungkinan berguna dan mudah dilakukan.
Mengutip:
sumber
Saya sudah melakukan banyak ini, dan ya itu menyebalkan.
Beberapa tips:
throwable
bidang dan periksa ditearDown
(lihat Daftar 1). Jika Anda menangkap pengecualian buruk di utas lain, cukup tetapkan itu untuk dibuang.AtomicBoolean
dalam tes Anda. Ini adalah thread yang aman, dan Anda akan sering membutuhkan jenis referensi akhir untuk menyimpan nilai dari kelas panggilan balik dan sejenisnya. Lihat contoh di Listing 3.@Test(timeout=60*1000)
), karena tes konkurensi kadang-kadang dapat menggantung selamanya ketika mereka rusak.Listing 1:
Listing 2:
Listing 3:
sumber
Menguji kode MT untuk kebenaran, seperti yang telah disebutkan, merupakan masalah yang cukup sulit. Pada akhirnya, hal itu dilakukan untuk memastikan bahwa tidak ada ras data yang disinkronkan secara salah dalam kode Anda. Masalahnya adalah ada banyak kemungkinan eksekusi thread (interleavings) di mana Anda tidak memiliki banyak kontrol (pastikan untuk membaca ini artikel , meskipun). Dalam skenario sederhana dimungkinkan untuk benar-benar membuktikan kebenaran dengan alasan tetapi ini biasanya tidak terjadi. Terutama jika Anda ingin menghindari / meminimalkan sinkronisasi dan tidak menggunakan opsi sinkronisasi yang paling jelas / termudah.
Pendekatan yang saya ikuti adalah menulis kode uji yang sangat konkuren untuk membuat kemungkinan ras data yang tidak terdeteksi terjadi. Dan kemudian saya menjalankan tes-tes itu untuk beberapa waktu :) Saya pernah menemukan sebuah pembicaraan di mana beberapa ilmuwan komputer di mana memamerkan alat semacam itu melakukan ini (secara acak merancang tes dari spesifikasi dan kemudian menjalankannya secara liar, bersamaan, memeriksa invarian yang ditentukan untuk dilanggar).
Ngomong-ngomong, saya pikir aspek pengujian kode MT ini belum disebutkan di sini: identifikasi invarian dari kode yang dapat Anda periksa secara acak. Sayangnya, menemukan invarian tersebut juga merupakan masalah yang cukup sulit. Juga mereka mungkin tidak tahan sepanjang waktu selama eksekusi, jadi Anda harus menemukan / menegakkan poin eksekusi di mana Anda dapat mengharapkannya benar. Membawa eksekusi kode ke keadaan seperti itu juga merupakan masalah yang sulit (dan mungkin akan menimbulkan masalah konkurensi. Wah, ini sangat sulit!
Beberapa tautan menarik untuk dibaca:
sumber
Pete Goodliffe memiliki seri pengujian unit pada kode ulir .
Sulit. Saya mengambil jalan keluar yang lebih mudah dan mencoba untuk menjaga kode threading diabstraksi dari tes yang sebenarnya. Pete memang menyebutkan bahwa cara saya melakukannya salah, tetapi saya punya pemisahan yang benar atau saya baru saja beruntung.
sumber
Untuk Java, lihat bab 12 dari JCIP . Ada beberapa contoh konkret penulisan deterministik, tes unit multi-utas untuk setidaknya menguji kebenaran dan invarian kode konkuren.
Keamanan benang "terbukti" dengan unit test jauh lebih mudah. Keyakinan saya adalah bahwa ini lebih baik dilayani oleh pengujian integrasi otomatis pada berbagai platform / konfigurasi.
sumber
Saya suka menulis dua atau lebih metode pengujian untuk dieksekusi pada thread paralel, dan masing-masing membuat panggilan ke objek yang diuji. Saya telah menggunakan panggilan Sleep () untuk mengoordinasikan urutan panggilan dari utas berbeda, tapi itu tidak terlalu bisa diandalkan. Ini juga jauh lebih lambat karena Anda harus tidur cukup lama sehingga waktunya biasanya bekerja.
Saya menemukan pustaka TC Java Multithreaded dari grup yang sama yang menulis FindBugs. Ini memungkinkan Anda menentukan urutan acara tanpa menggunakan Sleep (), dan itu dapat diandalkan. Saya belum mencobanya.
Keterbatasan terbesar untuk pendekatan ini adalah hanya memungkinkan Anda menguji skenario yang Anda curigai akan menimbulkan masalah. Seperti yang orang lain katakan, Anda benar-benar perlu mengisolasi kode multithreaded Anda ke sejumlah kecil kelas sederhana untuk memiliki harapan untuk menguji mereka secara menyeluruh.
Setelah Anda dengan hati-hati menguji skenario yang Anda harapkan menyebabkan masalah, tes tidak ilmiah yang melempar banyak permintaan simultan di kelas untuk sementara waktu adalah cara yang baik untuk mencari masalah yang tidak terduga.
Pembaruan: Saya telah bermain sedikit dengan pustaka TC Java Multithreaded, dan berfungsi dengan baik. Saya juga telah mem-porting beberapa fitur-fiturnya ke versi .NET yang saya sebut TickingTest .
sumber
Saya menangani tes unit komponen ulir dengan cara yang sama saya menangani uji unit apa pun, yaitu dengan inversi kerangka kontrol dan isolasi. Saya mengembangkan di arena .Net dan di luar kotak threading (antara lain) sangat sulit (saya katakan hampir tidak mungkin) untuk sepenuhnya mengisolasi.
Karena itu saya telah menulis pembungkus yang terlihat seperti ini (disederhanakan):
Dari sana saya dapat dengan mudah menyuntikkan IThreadingManager ke komponen saya dan menggunakan kerangka isolasi pilihan saya untuk membuat thread berperilaku seperti yang saya harapkan selama pengujian.
Sejauh ini itu bekerja sangat baik untuk saya, dan saya menggunakan pendekatan yang sama untuk kumpulan thread, hal-hal di System.Environment, Sleep dll.
sumber
Lihatlah jawaban terkait saya di
Merancang kelas Uji untuk Penghalang kustom
Itu bias terhadap Jawa tetapi memiliki ringkasan yang masuk akal dari opsi.
Singkatnya meskipun (IMO) itu bukan penggunaan beberapa kerangka kerja mewah yang akan memastikan kebenaran tetapi bagaimana Anda merancang kode multithreaded Anda. Memisahkan masalah (konkurensi dan fungsionalitas) sangat membantu meningkatkan kepercayaan diri.Perangkat Lunak Orientasi Obyek yang Tumbuh Dipandu Oleh Pengujian menjelaskan beberapa opsi yang lebih baik daripada yang saya bisa.
Analisis statis dan metode formal (lihat, Concurrency: Model Negara dan Program Java ) adalah sebuah pilihan, tetapi saya telah menemukan mereka menjadi penggunaan terbatas dalam pengembangan komersial.
Jangan lupa bahwa tes gaya beban / rendam jarang dijamin untuk menyoroti masalah.
Semoga berhasil!
sumber
tempus-fugit
perpustakaan Anda di sini, yanghelps write and test concurrent code
;)Saya baru saja menemukan (untuk Java) alat yang disebut Threadsafe. Ini adalah alat analisis statis mirip dengan findbugs tetapi khusus untuk menemukan masalah multi-threading. Ini bukan pengganti untuk pengujian tetapi saya dapat merekomendasikannya sebagai bagian dari penulisan Java multi-threaded yang andal.
Ia bahkan menangkap beberapa masalah potensial yang sangat halus di sekitar hal-hal seperti subsumsi kelas, mengakses objek yang tidak aman melalui kelas bersamaan dan menemukan pengubah volatil yang hilang saat menggunakan paradigma penguncian diperiksa ganda.
Jika Anda menulis Java multithreaded mencobanya.
sumber
Artikel berikut menyarankan 2 solusi. Membungkus semaphore (CountDownLatch) dan menambahkan fungsionalitas seperti mengeksternalisasi data dari utas internal. Cara lain untuk mencapai tujuan ini adalah dengan menggunakan Thread Pool (lihat Tempat Menarik).
Sprinkler - Objek sinkronisasi lanjutan
sumber
Saya menghabiskan sebagian besar minggu lalu di perpustakaan universitas mempelajari debugging kode bersamaan. Masalah utama adalah kode konkuren adalah non-deterministik. Biasanya, debugging akademik telah jatuh ke dalam salah satu dari tiga kubu di sini:
Sekarang, seperti yang diperhatikan oleh komentator di atas, Anda dapat merancang sistem konkuren Anda menjadi keadaan yang lebih deterministik. Namun, jika Anda tidak melakukannya dengan benar, Anda kembali merancang sistem sekuensial lagi.
Saran saya adalah untuk fokus pada memiliki protokol desain yang sangat ketat tentang apa yang di-threaded dan apa yang tidak di-threaded. Jika Anda membatasi antarmuka Anda sehingga ada ketergantungan minimal antara elemen, itu jauh lebih mudah.
Semoga berhasil, dan terus kerjakan masalah tersebut.
sumber
Saya memiliki tugas yang tidak menguntungkan untuk menguji kode berulir dan mereka jelas merupakan tes tersulit yang pernah saya tulis.
Saat menulis tes saya, saya menggunakan kombinasi delegasi dan acara. Pada dasarnya ini semua tentang menggunakan
PropertyNotifyChanged
acara denganWaitCallback
atau semacamnyaConditionalWaiter
jajak pendapat itu.Saya tidak yakin apakah ini pendekatan terbaik, tetapi itu berhasil bagi saya.
sumber
Dengan asumsi di bawah kode "multi-threaded" berarti sesuatu itu
Dengan kata lain kita berbicara tentang pengujian kelas-metode / unit / unit thread-safe kustom - yang seharusnya menjadi binatang yang sangat langka saat ini.
Karena binatang buas ini langka, pertama-tama kita perlu memastikan bahwa ada semua alasan yang sah untuk menuliskannya.
Langkah 1. Pertimbangkan mengubah kondisi dalam konteks sinkronisasi yang sama.
Saat ini mudah untuk menulis kode konkuren dan asinkron yang dapat dikomposisikan di mana IO atau operasi lambat lainnya diturunkan ke latar belakang tetapi keadaan bersama diperbarui dan dipertanyakan dalam satu konteks sinkronisasi. mis. async / menunggu tugas dan Rx dalam .NET dll. - semuanya dapat diuji dengan desain, "nyata" Tugas dan penjadwal dapat diganti untuk membuat pengujian deterministik (namun ini di luar ruang lingkup pertanyaan).
Mungkin terdengar sangat terbatas tetapi pendekatan ini bekerja dengan sangat baik. Dimungkinkan untuk menulis seluruh aplikasi dengan gaya ini tanpa perlu membuat status utas aman (saya lakukan).
Langkah 2. Jika memanipulasi keadaan bersama pada konteks sinkronisasi tunggal sama sekali tidak mungkin.
Pastikan roda tidak diciptakan kembali / pasti tidak ada alternatif standar yang dapat disesuaikan untuk pekerjaan itu. Seharusnya kode itu sangat kohesif dan terkandung dalam satu unit misalnya dengan peluang yang baik itu adalah kasus khusus dari beberapa struktur data aman-benang standar seperti peta hash atau koleksi atau apa pun.
Catatan: jika kode besar / mencakup beberapa kelas DAN membutuhkan manipulasi keadaan multi-thread maka ada peluang yang sangat tinggi bahwa desain tidak baik, pertimbangkan kembali Langkah 1
Langkah 3. Jika langkah ini tercapai, kita perlu menguji kelas / metode / unit thread-safe stateful kami sendiri .
Saya akan sangat jujur: Saya tidak pernah harus menulis tes yang tepat untuk kode tersebut. Sebagian besar waktu saya lolos pada Langkah 1, kadang-kadang pada Langkah 2. Terakhir kali saya harus menulis kode khusus thread-safe bertahun-tahun yang lalu sebelum saya mengadopsi unit testing / mungkin saya tidak perlu menulisnya dengan pengetahuan saat ini pula.
Jika saya benar-benar harus menguji kode tersebut ( akhirnya, jawaban aktual ) maka saya akan mencoba beberapa hal di bawah ini
Pengujian stres non-deterministik. mis. jalankan 100 utas secara bersamaan dan periksa apakah hasil akhirnya konsisten. Ini lebih tipikal untuk pengujian level / integrasi yang lebih tinggi dari beberapa skenario pengguna tetapi juga dapat digunakan pada level unit.
Paparkan beberapa 'kait' uji di mana tes dapat menyuntikkan beberapa kode untuk membantu membuat skenario deterministik di mana satu utas harus melakukan operasi sebelum yang lain. Seburuk itu, saya tidak bisa memikirkan sesuatu yang lebih baik.
Pengujian yang digerakkan oleh penundaan untuk membuat thread berjalan dan melakukan operasi dalam urutan tertentu. Sebenarnya, tes semacam itu juga non-deterministik (ada kemungkinan sistem membekukan / menghentikan pengumpulan GC dunia yang dapat mendistorsi penundaan yang diatur sebelumnya), juga jelek tetapi memungkinkan untuk menghindari kaitan.
sumber
Untuk kode J2E, saya telah menggunakan SilkPerformer, LoadRunner dan JMeter untuk pengujian konkurensi utas. Mereka semua melakukan hal yang sama. Pada dasarnya, mereka memberi Anda antarmuka yang relatif sederhana untuk mengelola versi server proxy mereka, diperlukan, untuk menganalisis aliran data TCP / IP, dan mensimulasikan beberapa pengguna membuat permintaan simultan ke server aplikasi Anda. Server proksi dapat memberi Anda kemampuan untuk melakukan hal-hal seperti menganalisis permintaan yang dibuat, dengan menyajikan seluruh halaman dan URL yang dikirim ke server, serta respons dari server, setelah memproses permintaan.
Anda dapat menemukan beberapa bug dalam mode http tidak aman, di mana Anda setidaknya bisa menganalisis data formulir yang sedang dikirim, dan secara sistematis mengubahnya untuk setiap pengguna. Tetapi tes yang sebenarnya adalah ketika Anda menjalankan di https (Lapisan Socket Aman). Kemudian, Anda juga harus bersaing dengan secara sistematis mengubah data sesi dan cookie, yang bisa sedikit lebih berbelit-belit.
Bug terbaik yang pernah saya temukan, saat menguji konkurensi, adalah ketika saya menemukan bahwa pengembang telah mengandalkan pengumpulan sampah Java untuk menutup permintaan koneksi yang dibuat saat login, ke server LDAP, saat masuk. Hal ini mengakibatkan pengguna terekspos. ke sesi pengguna lain dan hasil yang sangat membingungkan, ketika mencoba menganalisis apa yang terjadi ketika server dibuat berlutut, hampir tidak dapat menyelesaikan satu transaksi, setiap beberapa detik.
Pada akhirnya, Anda atau seseorang mungkin harus bekerja keras dan menganalisis kode untuk kesalahan seperti yang saya sebutkan tadi. Dan diskusi terbuka lintas departemen, seperti yang terjadi, ketika kami membuka masalah yang dijelaskan di atas, sangat berguna. Tetapi alat ini adalah solusi terbaik untuk menguji kode multi-threaded. JMeter adalah open source. SilkPerformer dan LoadRunner adalah hak milik. Jika Anda benar-benar ingin tahu apakah aplikasi Anda aman, itulah yang dilakukan anak-anak besar. Saya telah melakukan ini untuk perusahaan yang sangat besar secara profesional, jadi saya tidak menebak. Saya berbicara dari pengalaman pribadi.
Peringatan: diperlukan beberapa saat untuk memahami alat-alat ini. Ini tidak akan menjadi masalah hanya dengan menginstal perangkat lunak dan menjalankan GUI, kecuali Anda sudah memiliki beberapa paparan pemrograman multi-threaded. Saya telah mencoba mengidentifikasi 3 kategori penting bidang yang perlu dipahami (formulir, sesi, dan data cookie), dengan harapan bahwa setidaknya mulai dengan memahami topik-topik ini akan membantu Anda fokus pada hasil yang cepat, sebagai lawan dari harus membaca keseluruhan seluruh dokumentasi.
sumber
Concurrency adalah interaksi yang kompleks antara model memori, perangkat keras, cache dan kode kami. Dalam kasus Jawa, setidaknya tes semacam itu sebagian telah ditangani terutama oleh jcstress . Pembuat perpustakaan itu dikenal sebagai penulis banyak fitur konkurensi JVM, GC dan Java.
Tetapi bahkan perpustakaan ini membutuhkan pengetahuan yang baik tentang spesifikasi Java Memory Model sehingga kami tahu persis apa yang kami uji. Tapi saya pikir fokus dari upaya ini adalah mircobenchmarks. Bukan aplikasi bisnis besar.
sumber
Ada artikel tentang topik tersebut, menggunakan Rust sebagai bahasa dalam kode contoh:
https://medium.com/@polyglot_factotum/rust-concurrency-five-easy-pieces-871f1c62906a
Singkatnya, triknya adalah untuk menulis logika konkursi Anda sehingga kuat untuk non-determinisme yang terlibat dengan beberapa utas eksekusi, menggunakan alat seperti saluran dan condvars.
Kemudian, jika itu adalah cara Anda menyusun "komponen" Anda, cara termudah untuk mengujinya adalah dengan menggunakan saluran untuk mengirim pesan kepada mereka, dan kemudian memblokir saluran lain untuk menyatakan bahwa komponen tersebut mengirim pesan yang diharapkan.
Artikel yang ditautkan ke sepenuhnya ditulis menggunakan unit-tes.
sumber
Jika Anda menguji Thread baru yang sederhana (runnable) .run () Anda dapat mengejek Thread untuk menjalankan runnable secara berurutan
Misalnya, jika kode objek yang diuji meminta utas baru seperti ini
Kemudian mengejek Thread baru dan menjalankan argumen runnable secara berurutan dapat membantu
sumber
(jika mungkin) tidak menggunakan utas, gunakan aktor / objek aktif. Mudah diuji.
sumber
Anda dapat menggunakan EasyMock.makeThreadSafe untuk membuat pengujian instance threadsafe
sumber