praktik terbaik saat pengujian unit untuk pengembangan tertanam

45

Saya mencari beberapa strategi praktik terbaik untuk kode pengujian unit yang ditulis untuk sistem tertanam. Dengan sistem tertanam, maksud saya kode seperti driver perangkat, penangan ISR dll, hal-hal yang cukup dekat dengan logam.

Sebagian besar unit test tidak mungkin dilakukan tanpa mengujinya pada perangkat keras dengan bantuan ICE. Terkadang, unit tertanam juga perlu dihubungkan ke stimulus lain seperti sakelar mekanis, motor stepper, dan bola lampu. Ini biasanya terjadi dalam mode manual, otomatisasi akan bagus tetapi sulit dan mahal untuk dicapai.

Memperbarui

Saya menemukan kerangka kerja pengujian C yang tampaknya cukup berhasil dalam menguji proyek tertanam. Ini menggunakan ide-ide perangkat keras mengejek. Lihat Unity , CMock , dan mungkin Ceedling .

Perbarui 06Jul2016

Datang di cmocka - tampaknya lebih aktif dikerjakan.

tehnyit
sumber
1
Dalam keadaan yang sama, kami memilih Cmocka
Mawg
Saya telah menulis tutorial yang sangat menyeluruh pada topik: Pengujian unit aplikasi C tertanam dengan Ceedling
Dmitry Frank

Jawaban:

28

Saya akan abstrak jauh dari dependensi perangkat keras pada langkah sedini mungkin, dan membangun sistem pada emulasi perangkat lunak / memanfaatkan uji, memungkinkan segala macam kerangka kerja pengujian. Seringkali PC pengembangan saya digunakan untuk menguji sebanyak 95% atau lebih dari sistem yang lengkap. Biaya overhead tambahan (lapisan abstraksi lain) dengan mudah dimenangkan kembali oleh kode pembersih yang dihasilkan sebagai akibat dari abstraksi itu.

Pengujian bagian-bagian yang benar-benar baremetal dari sistem tertanam biasanya merupakan aplikasi terpisah (Uji unit?) Yang memalu firmware jauh melampaui apa yang bahkan dapat dicapai oleh aplikasi. Otomasi dapat dilakukan - dengan biaya, tetapi tidak khas.

Kecuali, yaitu, Anda memiliki anggaran untuk membangun harness perangkat keras unit test termasuk ICE lengkap. Ini benar-benar baik karena umumnya tes fungsional kecil.

mattnz
sumber
Ini dikombinasikan dengan jonathan cline ieee jawaban adalah strategi yang sukses. Gunakan abstraksi untuk membuat sebagian besar kode dapat diuji, dan menggunakan kerangka uji sederhana untuk menguji bit yang tidak dapat diabstraksikan pada perangkat keras sebenarnya. Saya pribadi melihat pekerjaan ini dengan berbagai platform.
Tim Williscroft
3
Setiap produk yang kami buat memiliki Hardware Abstraction Layer dengan implementasi driver untuk platform target dan PC. Ini memungkinkan kita menjalankan unit test dengan mudah. Keuntungan lain: kita juga dapat menjalankan tes sistem cepat dan mengembangkan sebagian besar perangkat lunak tanpa perangkat keras apa pun (seperti yang tersedia kemudian).
MaR
15

Alat yang diperlukan untuk dikembangkan adalah injektor sinyal. Sistem tertanam akan memiliki beberapa cara untuk berinteraksi dengan sistem host (biasanya melalui port serial yang disediakan untuk debugging). Gunakan ini untuk mengirim data uji (opsi terbaik adalah singkat ascii diformat sehingga mudah disimulasikan oleh manusia juga).

Saya sepenuhnya tidak setuju dengan bagian dari pertanyaan Anda ini: "otomasi akan bagus tetapi sulit dan mahal untuk dicapai."

Menggunakan TeraTerm sebagai injektor sinyal port serial, dan menulis beberapa makro TeraTerm (membutuhkan waktu sekitar 20 menit), ada serangkaian besar tes otomatis yang dapat dijalankan terhadap bagian mana pun dari sistem tertanam - apakah lapisan driver, O / S, layer 4-5, dll. TeraTerm: http://en.sourceforge.jp/projects/ttssh2/

Jika port serial tidak tersedia pada sistem tertanam, maka gunakan alat perangkat keras untuk mengubah data port USB / serial menjadi sinyal digital (juga murah dan mudah dicapai). Ketika Anda membaca ini, saya menggunakan papan mikrokontroler $ 30 (UBW: http://www.schmalzhaus.com/UBW32/ ) untuk menguji sistem tertanam untuk produksi, dengan menyuntikkan stimulus melalui makro TeraTerm yang dikirim melalui USB / serial ke mikrokontroler, yang menjalankan firmware yang dimodifikasi yang menjalankan input digital dan memonitor output digital dari sistem target yang disematkan. Sehubungan dengan ini, kami mengembangkan skrip python (menggunakan pyserial dan pexpect) untuk mengotomatisasi injeksi data dan validasi data. Tidak ada yang sulit dan tidak ada yang mahal. Dalam pengalaman saya, para manajer menghabiskan banyak uang (seperti $ 30.000 alat uji) ketika tim uji tidak berpengalaman dan tidak dapat memahami solusi mudah ini - sayangnya, tujuan umum peralatan besi besar sering tidak termasuk kasus uji yang menangkap waktu terburuk / etc dari sistem target. Jadi metode yang murah lebih disukai untuk cakupan tes. Percaya atau tidak.

Jonathan Cline IEEE
sumber
1
Yah, saya membuat pernyataan mahal karena saya bekerja di industri otomotif dan semuanya perlu deterministik, berulang dan biasanya membutuhkan beberapa insinyur untuk dikembangkan. Juga ketika lebih banyak item digunakan dalam rantai pengujian, pemeliharaan juga menjadi masalah. Terima kasih telah memberi tahu kami tentang UBW, sepertinya ini pilihan yang bagus.
tehnyit
2
Hanya saja jangan mulai saya di LabView .. itu hal yang mengerikan biasanya.
Jonathan Cline IEEE
1
Teknisi pengujian kami menyukai LabView, saya sendiri tidak begitu memahaminya.
tehnyit
Ini cukup dekat dengan apa yang saya lakukan untuk berbagai pengujian, hanya saya menggunakan Python dan pustaka serial mereka. Saya kemudian bisa memasukkan tes tingkat rendah saya ke unit penguji Python bersama dengan sesuatu seperti Flask / Qt untuk memberikan antarmuka yang mudah digunakan juga.
radix07
5

Ini adalah masalah yang sangat sulit.

Saya sebenarnya telah merancang unit harness pengujian untuk sistem tertanam, yang akan memungkinkan simulasi acara perangkat keras / interupsi, dan mengontrol waktu pelaksanaan (untuk memastikan kami mencakup semua kemungkinan interleavings karena konkurensi), dan butuh tim dari programmer lebih dari 2 tahun untuk benar-benar mengimplementasikannya dan membuatnya bekerja. Proyek itu adalah pengembangan hak milik, tetapi proyek serupa (lebih sederhana dalam desain) tersedia di sini .

Jadi ya, otomatisasi akan bagus. Ya, itu sangat sulit dan mahal untuk dicapai. Ya, terkadang Anda harus melakukan itu. Meskipun jarang, dalam pengalaman saya dalam banyak kasus, lebih cepat dan lebih murah untuk menggunakan motor stepper dan bola lampu dan membuatnya semuanya bekerja secara manual.

littleadv
sumber
Saya telah menemukan bahwa unit itu secara manual rentan terhadap kesalahan, biasanya dalam menghasilkan stimulus, atau mengukur hasilnya. Terutama benar jika unit test rumit. Jika Anda harus mengulang tes unit lagi, itu akan lebih rentan terhadap kesalahan.
tehnyit
@tehnyit - ya, itulah alasan kami memutuskan untuk mengembangkan sistem otomasi. Kadang-kadang hal-hal tidak dapat dilakukan secara manual sama sekali, namun unit test harus komprehensif dan mencakup masalah waktu. Jadi Anda tidak punya banyak pilihan, tetapi otomatisasi pada tingkat ini adalah hal yang sangat mahal untuk dilakukan.
littleadv
4

Sunting: jawaban saya dekat dengan mattnz, saya pikir ...


Saya ingin mengaitkan masalah ini dengan orang lain, semua tes yang bergantung pada sesuatu di luar kode Anda (seperti jam sistem, sistem file persisten atau database, menghubungi layanan web eksternal ...). Saya menyarankan kebijakan yang sama untuk mereka semua, mengisolasi dua level dalam dua lapisan kode.

Menguji operasi eksternal tunggal

Anda mungkin ingin menguji secara fisik setiap operasi. Periksa apakah jam sistem memberikan waktu yang tepat, periksa file yang benar-benar mengingat apa yang telah ditulis, periksa perangkat yang menerima satu operasi ...

Tes-tes ini:

  • harus sesederhana mungkin: tidak ada algoritma apa pun, tidak ada kondisi atau loop
  • mungkin tergantung pada pesanan dan tergantung pada mesin: jadi Anda harus mengikuti perintah yang ketat, dan ulangi pada setiap perangkat keras
  • sebagian besar stabil selama proyek Anda, sehingga Anda tidak perlu menjalankannya sesering itu
  • jadi menjalankannya secara manual adalah opsi; otomasi bahkan lebih baik, jika tidak terlalu rumit
  • Perhatikan bahwa apa yang sedang diuji bukan kode Anda , itu adalah alat yang dibutuhkan kode Anda ... Jadi, menguji ini mungkin opsional untuk Anda, mungkin dilakukan oleh tim yang berbeda ...

Menguji logika (kode, algoritma) yang menghubungkan operasi eksternal

Dengan memiliki lapisan kode untuk membuat operasi eksternal yang sebenarnya, dengan menyembunyikannya dari antarmuka yang dapat Anda tiru dengan mudah, logika Anda tidak lagi bergantung pada perangkat fisik yang sebenarnya ...

Anda dapat menguji secara sederhana, seperti proyek biasa, Anda tidak lagi berada dalam kode sulit-untuk-uji yang tertanam .

KLE
sumber
3

Simulator CPU tertanam umumnya dapat diprogram untuk juga mensimulasikan perangkat keras. Semua teknologi virtualisasi selain Xen melakukan itu. Tetapi Anda perlu menulis kode yang berpura-pura memiliki beberapa register di beberapa alamat fisik atau, pada x86, alamat pada bus I / O, dan kemudian Anda perlu merespons membaca dan menulis ke alamat-alamat ini seolah-olah perangkat lunak Anda adalah fisik. chip yang kontrol dan status registernya sedang diakses.

Jika Anda ingin melakukan ini, saya akan menyarankan memodifikasi QEMU. Tapi itu tidak mudah. Hal semacam ini umumnya hanya dilakukan ketika Anda merancang chip khusus dengan mikrokontroler dan beberapa core lainnya untuk I / O Anda.

Sistem pengembangan yang dijual oleh ARM Holdings menyediakan ini dan kemungkinan lebih mudah untuk dikerjakan daripada meretas QEMU, tetapi sangat mahal.

Ada beberapa emulator ARM Open Source yang menjalankan subrutin tunggal, yang dengan sendirinya dapat memanggil subrutin lain, yang dapat Anda gunakan untuk debugging tuning kinerja subrutin yang tidak bergantung pada akses perangkat keras. Saya menggunakan salah satu dari ini untuk sukses besar untuk mengoptimalkan enkripsi AES untuk ARM7TDMI.

Anda bisa menulis unit test harness sederhana dalam C atau C ++, menghubungkan kelas atau subrutin yang sedang diuji, lalu menjalankannya di simulator.

Saya telah merenungkan masalah yang sama selama bertahun-tahun, bagaimana unit menguji Linux atau kode kernel Mac OS X. Seharusnya mungkin, tetapi saya belum pernah benar-benar mencobanya. Salah satunya adalah membangun kernel penuh daripada menguji kode Anda secara terpisah, dengan kerangka kerja unit test yang terhubung langsung ke kernel Anda. Anda kemudian akan mematikan tes unit dari beberapa jenis antarmuka eksternal.

Mungkin akan lebih produktif untuk menggunakan alat jangkauan kode, kemudian menguji firmware Anda sebagai paket lengkap melalui antarmuka eksternal. Alat jangkauan akan menemukan jalur kode yang belum diuji, sehingga Anda kemudian dapat menambahkan tes eksternal tambahan dalam upaya untuk mendapatkan lebih banyak cakupan.

Mike Crawford
sumber
3

Seperti halnya TDD yang tidak tertanam, objek tiruan sudah pasti adalah teman Anda.

Menjaga antarmuka ke perangkat keras dasar Anda bersih dan sederhana sehingga segala sesuatu di atas level terendah dapat diejek dan Anda akan memiliki waktu yang jauh lebih mudah - jika Anda merancang aplikasi yang tertanam dengan mudah diingat maka pengujian akan selalu berjalan jauh lebih lancar .

Juga, hanya karena Anda mungkin tidak dapat menguji on-line sampai sangat terlambat dalam proyek tidak berarti bahwa Anda tidak harus menyiapkan serangkaian tes on-line juga.

Ini seharusnya (awalnya) hanya perlu menguji bit yang tidak dapat diuji secara offline. Tentu, ini bukan TDD (karena Anda membuat tes di muka) tetapi pengembangan TDD offline Anda akan memberi Anda ide yang bagus tentang seperti apa tampilan antarmuka perangkat keras Anda dan dengan demikian tes online apa yang perlu Anda lakukan.

Juga, jika pengembangan online lebih mahal daripada pengembangan offline (seperti halnya di tempat saya bekerja) maka itu bisa menghemat banyak waktu online dengan memiliki serangkaian tes yang dipahami dengan baik untuk dijalankan.

Mark Booth
sumber
+1 untuk membawa benda tiruan ke piring, @mark. Satu masalah adalah memastikan keakuratan objek tiruan, yang berarti memahami objek yang akan diejek harus cukup dalam. Ini bagus karena memaksa pengembang untuk memahami perilaku objek eksternal yang berinteraksi dengannya.
tehnyit
1

Dalam pengembangan tertanam Anda sering melakukan pemindaian batas untuk memverifikasi seluruh aplikasi (termasuk perangkat keras) berfungsi. Lihat juga JTAG untuk debugging sistem.

Menguji rutinitas perangkat lunak murni tanpa tautan ke perangkat keras dapat dilakukan dengan kerangka kerja Uji Unit C standar seperti Periksa . Namun waspadalah terhadap keterbatasan memori (terutama stackspace dll pada perangkat kecil). Ketahui kontrak Anda! Anda juga dapat mencoba untuk mengabstraksikan rutin perangkat lunak dari perangkat keras untuk mendapatkan cakupan uji yang lebih besar tetapi ini biasanya mahal dalam hal kinerja pada perangkat yang disematkan seperti PIC kecil atau AVR. Namun, Anda dapat mengejek port perangkat keras untuk mencapai cakupan yang lebih besar (dan tentu saja Anda dapat menguji tiruan itu juga).

Anda juga dapat mencoba menggunakan emulator untuk chip atau rangkaian simluator, tetapi alat semacam ini mahal (terutama dalam kombinasi) dan rumit.

Elang
sumber
Setuju dengan pemindaian batas dan JTAG, tetapi, karena desain perangkat keras, itu tidak selalu mungkin atau tersedia.
tehnyit