Jangan Jalankan Tes Unit pada Perangkat Arduino atau Emulator
Kasing terhadap mikrokontroler Perangkat / Emulator / tes berbasis Sim
Ada banyak diskusi tentang apa arti unit test dan saya tidak benar-benar mencoba untuk membuat argumen tentang itu di sini. Posting ini tidak
memberitahu Anda untuk menghindari semua pengujian praktis pada perangkat keras target utama Anda. Saya mencoba membuat poin tentang mengoptimalkan siklus umpan balik pengembangan Anda dengan menghilangkan perangkat keras target Anda dari tes yang paling biasa dan sering. Unit-unit yang diuji diasumsikan jauh lebih kecil dari keseluruhan proyek.
Tujuan pengujian unit adalah untuk menguji kualitas kode Anda sendiri. Tes unit umumnya tidak boleh menguji fungsionalitas faktor di luar kendali Anda.
Pikirkan seperti ini: Bahkan jika Anda menguji fungsionalitas perpustakaan Arduino, perangkat keras mikrokontroler, atau emulator, sama sekali tidak mungkin bagi hasil tes tersebut untuk memberi tahu Anda apa pun tentang kualitas pekerjaan Anda sendiri. Oleh karena itu, jauh lebih berharga dan efisien untuk menulis unit test yang tidak berjalan pada perangkat target (atau emulator).
Pengujian yang sering dilakukan pada perangkat keras target Anda memiliki siklus yang sangat lambat:
- Tweak kode Anda
- Kompilasi dan unggah ke perangkat Arduino
- Amati perilaku dan tebak apakah kode Anda melakukan apa yang Anda harapkan
- Ulang
Langkah 3 sangat tidak menyenangkan jika Anda berharap mendapatkan pesan diagnostik melalui port serial tetapi proyek Anda sendiri perlu menggunakan port serial perangkat keras Arduino Anda saja. Jika Anda berpikir bahwa pustaka SoftwareSerial mungkin membantu, Anda harus tahu bahwa melakukan hal itu kemungkinan akan mengganggu fungsionalitas yang memerlukan waktu akurat seperti menghasilkan sinyal lain pada saat yang sama. Masalah ini terjadi pada saya.
Sekali lagi, jika Anda menguji sketsa Anda menggunakan emulator dan rutinitas kritis waktu Anda berjalan dengan sempurna sampai Anda mengunggah ke Arduino yang sebenarnya, maka satu-satunya pelajaran yang akan Anda pelajari adalah bahwa emulator itu cacat - dan mengetahui hal ini masih tidak mengungkapkan apa pun tentang kualitas pekerjaan Anda sendiri .
Jika konyol untuk menguji pada perangkat atau emulator, apa yang harus saya lakukan?
Anda mungkin menggunakan komputer untuk mengerjakan proyek Arduino Anda. Komputer itu adalah urutan besarnya lebih cepat dari mikrokontroler. Tulis tes untuk dibangun dan dijalankan di komputer Anda .
Ingat, perilaku perpustakaan dan mikrokontroler Arduino harus dianggap benar atau setidaknya secara konsisten salah .
Ketika tes Anda menghasilkan output yang bertentangan dengan harapan Anda, maka kemungkinan Anda memiliki cacat pada kode Anda yang diuji. Jika hasil pengujian Anda sesuai dengan harapan Anda, tetapi program tersebut tidak berlaku dengan benar ketika Anda mengunggahnya ke Arduino, maka Anda tahu bahwa pengujian Anda didasarkan pada asumsi yang salah dan Anda kemungkinan memiliki tes yang cacat. Dalam kedua kasus tersebut, Anda akan diberi wawasan nyata tentang apa yang harus diubah oleh kode Anda selanjutnya. Kualitas umpan balik Anda ditingkatkan dari " ada yang rusak" menjadi " kode khusus ini rusak" .
Cara Membangun dan Menjalankan Tes di PC Anda
Hal pertama yang perlu Anda lakukan adalah mengidentifikasi tujuan pengujian Anda . Pikirkan bagian mana dari kode Anda sendiri yang ingin Anda uji dan kemudian pastikan untuk membangun program Anda sedemikian rupa sehingga Anda dapat mengisolasi bagian - bagian terpisah untuk pengujian.
Jika bagian yang ingin Anda uji memanggil fungsi Arduino, Anda harus memberikan penggantian tiruan dalam program pengujian Anda. Ini jauh lebih sedikit dari yang terlihat. Mock-up Anda tidak harus melakukan apa pun selain memberikan input dan output yang dapat diprediksi untuk pengujian Anda.
Kode Anda sendiri yang ingin Anda uji perlu ada dalam file sumber selain sketsa .pde. Jangan khawatir, sketsa Anda masih akan dikompilasi bahkan dengan beberapa kode sumber di luar sketsa. Ketika Anda benar-benar turun ke sana, sedikit lebih dari titik masuk normal program Anda harus didefinisikan dalam file sketsa.
Yang tersisa hanyalah menulis tes yang sebenarnya dan kemudian mengompilasinya menggunakan kompiler C ++ favorit Anda! Ini mungkin paling baik digambarkan dengan contoh dunia nyata.
Contoh kerja aktual
Salah satu proyek kesayangan saya yang ditemukan di sini memiliki beberapa tes sederhana yang berjalan di PC. Untuk pengajuan jawaban ini, saya akan membahas bagaimana saya mengejek beberapa fungsi perpustakaan Arduino dan tes yang saya tulis untuk menguji tiruan tersebut. Ini tidak bertentangan dengan apa yang saya katakan sebelumnya tentang tidak menguji kode orang lain karena saya adalah orang yang menulis maket. Saya ingin sangat yakin bahwa tiruan saya benar.
Sumber mock_arduino.cpp, yang berisi kode yang menduplikasi beberapa fungsi dukungan yang disediakan oleh perpustakaan Arduino:
#include <sys/timeb.h>
#include "mock_arduino.h"
timeb t_start;
unsigned long millis() {
timeb t_now;
ftime(&t_now);
return (t_now.time - t_start.time) * 1000 + (t_now.millitm - t_start.millitm);
}
void delay( unsigned long ms ) {
unsigned long start = millis();
while(millis() - start < ms){}
}
void initialize_mock_arduino() {
ftime(&t_start);
}
Saya menggunakan mock-up berikut untuk menghasilkan output yang dapat dibaca ketika kode saya menulis data biner ke perangkat serial perangkat keras.
fake_serial.h
#include <iostream>
class FakeSerial {
public:
void begin(unsigned long);
void end();
size_t write(const unsigned char*, size_t);
};
extern FakeSerial Serial;
fake_serial.cpp
#include <cstring>
#include <iostream>
#include <iomanip>
#include "fake_serial.h"
void FakeSerial::begin(unsigned long speed) {
return;
}
void FakeSerial::end() {
return;
}
size_t FakeSerial::write( const unsigned char buf[], size_t size ) {
using namespace std;
ios_base::fmtflags oldFlags = cout.flags();
streamsize oldPrec = cout.precision();
char oldFill = cout.fill();
cout << "Serial::write: ";
cout << internal << setfill('0');
for( unsigned int i = 0; i < size; i++ ){
cout << setw(2) << hex << (unsigned int)buf[i] << " ";
}
cout << endl;
cout.flags(oldFlags);
cout.precision(oldPrec);
cout.fill(oldFill);
return size;
}
FakeSerial Serial;
dan akhirnya, program tes yang sebenarnya:
#include "mock_arduino.h"
using namespace std;
void millis_test() {
unsigned long start = millis();
cout << "millis() test start: " << start << endl;
while( millis() - start < 10000 ) {
cout << millis() << endl;
sleep(1);
}
unsigned long end = millis();
cout << "End of test - duration: " << end - start << "ms" << endl;
}
void delay_test() {
unsigned long start = millis();
cout << "delay() test start: " << start << endl;
while( millis() - start < 10000 ) {
cout << millis() << endl;
delay(250);
}
unsigned long end = millis();
cout << "End of test - duration: " << end - start << "ms" << endl;
}
void run_tests() {
millis_test();
delay_test();
}
int main(int argc, char **argv){
initialize_mock_arduino();
run_tests();
}
Posting ini cukup panjang, jadi silakan merujuk ke proyek saya di GitHub untuk melihat beberapa kasus uji lagi yang sedang beraksi. Saya menyimpan pekerjaan saya yang sedang berlangsung di cabang selain master, jadi periksa cabang-cabang itu untuk tes tambahan juga.
Saya memilih untuk menulis rutin pengujian ringan saya sendiri, tetapi kerangka kerja unit-test yang lebih kuat seperti CppUnit juga tersedia.