Arduino डिवाइस या एमुलेटर पर यूनिट टेस्ट न चलाएं
माइक्रोकंट्रोलर डिवाइस / एमुलेटर / सिम-आधारित परीक्षणों के खिलाफ मामला
यूनिट टेस्ट का क्या अर्थ है , इस बारे में बहुत चर्चा हो रही है और मैं वास्तव में उस बारे में कोई तर्क देने की कोशिश नहीं कर रहा हूं। यह पोस्ट
आपको अपने अंतिम लक्ष्य हार्डवेयर पर सभी व्यावहारिक परीक्षण से बचने के लिए नहीं कह रहा है । मैं आपके सबसे अधिक सांसारिक और अक्सर परीक्षणों से आपके लक्ष्य हार्डवेयर को समाप्त करके आपके विकास प्रतिक्रिया चक्र के अनुकूलन के बारे में एक बिंदु बनाने की कोशिश कर रहा हूं। परीक्षण के तहत इकाइयों को पूरे प्रोजेक्ट की तुलना में बहुत छोटा माना जाता है।
इकाई परीक्षण का उद्देश्य अपने स्वयं के कोड की गुणवत्ता का परीक्षण करना है। यूनिट परीक्षणों को आम तौर पर आपके नियंत्रण के बाहर कारकों की कार्यक्षमता का परीक्षण नहीं करना चाहिए।
इसके बारे में इस तरह से सोचें: यहां तक कि अगर आप Arduino लाइब्रेरी की कार्यक्षमता, माइक्रोकंट्रोलर हार्डवेयर, या एक एमुलेटर का परीक्षण करने के लिए थे, तो ऐसे परीक्षण परिणामों के लिए आपको अपने स्वयं के काम की गुणवत्ता के बारे में कुछ भी बताना बिल्कुल असंभव है । इसलिए, यूनिट परीक्षणों को लिखने के लिए यह अधिक मूल्यवान और कुशल है जो लक्ष्य डिवाइस (या एमुलेटर) पर नहीं चलते हैं।
आपके लक्ष्य हार्डवेयर पर बार-बार परीक्षण करने से दर्द का धीमा चक्र होता है:
- अपने कोड को ट्वीक करें
- संकलन और Arduino डिवाइस पर अपलोड करें
- व्यवहार का निरीक्षण करें और अनुमान लगाएं कि आपका कोड वह कर रहा है जो आप अपेक्षा करते हैं
- दोहराना
चरण 3 विशेष रूप से बुरा है यदि आप सीरियल पोर्ट के माध्यम से नैदानिक संदेश प्राप्त करने की उम्मीद करते हैं, लेकिन आपकी परियोजना को अपने Arduino के एकमात्र हार्डवेयर पोर्ट का उपयोग करने की आवश्यकता है। यदि आप सोच रहे थे कि SoftwareSerial पुस्तकालय मदद कर सकता है, तो आपको पता होना चाहिए कि ऐसा करने से किसी भी कार्यक्षमता को बाधित करने की संभावना है जो एक ही समय में अन्य संकेतों को उत्पन्न करने जैसे सटीक समय की आवश्यकता होती है। यह समस्या मुझे हुई है।
फिर से, यदि आप एक एमुलेटर का उपयोग करके अपने स्केच का परीक्षण करने के लिए थे और आपका समय-महत्वपूर्ण रूटीन पूरी तरह से चला गया था जब तक कि आप वास्तविक Arduino पर अपलोड नहीं किए जाते हैं, तो आप जो एकमात्र सबक सीखने जा रहे हैं वह यह है कि एमुलेटर त्रुटिपूर्ण है - और यह अभी भी जानना अपने काम की गुणवत्ता के बारे में कुछ भी नहीं बताता है ।
यदि यह उपकरण या एमुलेटर पर परीक्षण करने के लिए मूर्खतापूर्ण है, तो मुझे क्या करना चाहिए ?
आप शायद अपने Arduino प्रोजेक्ट पर काम करने के लिए कंप्यूटर का उपयोग कर रहे हैं। वह कंप्यूटर माइक्रोकंट्रोलर की तुलना में तेजी से परिमाण का आदेश है। अपने कंप्यूटर पर निर्माण और चलाने के लिए परीक्षण लिखें ।
याद रखें, Arduino लाइब्रेरी और माइक्रोकंट्रोलर के व्यवहार को सही माना जाना चाहिए या कम से कम लगातार गलत होना चाहिए ।
जब आपके परीक्षण आपकी अपेक्षाओं के विपरीत आउटपुट का उत्पादन करते हैं, तो आप की संभावना आपके कोड में एक दोष है जो परीक्षण किया गया था। यदि आपका परीक्षण आउटपुट आपकी अपेक्षाओं से मेल खाता है, लेकिन जब आप इसे Arduino पर अपलोड करते हैं, तो प्रोग्राम सही तरीके से व्यवहार नहीं करता है, तो आप जानते हैं कि आपके परीक्षण गलत मान्यताओं पर आधारित थे और आपके त्रुटिपूर्ण परीक्षण की संभावना है। किसी भी स्थिति में, आपको वास्तविक अंतर्दृष्टि दी जाएगी कि आपका अगला कोड क्या होना चाहिए। आपकी प्रतिक्रिया की गुणवत्ता " कुछ टूट गया है" से "यह विशिष्ट कोड टूट गया है" में सुधार हुआ है ।
अपने पीसी पर टेस्ट कैसे बनाएं और चलाएं
पहली चीज जो आपको करने की ज़रूरत है वह है आपके परीक्षण लक्ष्यों की पहचान करना । इस बारे में सोचें कि आप अपने स्वयं के कोड के किन हिस्सों का परीक्षण करना चाहते हैं और फिर अपने कार्यक्रम को इस तरह से बनाना सुनिश्चित करें कि आप परीक्षण के लिए असतत भागों को अलग कर सकें ।
यदि आप किसी भी Arduino फ़ंक्शन को कॉल करने के लिए इच्छित भागों का परीक्षण करना चाहते हैं, तो आपको अपने परीक्षण कार्यक्रम में नकली-अप प्रतिस्थापन प्रदान करना होगा। यह जितना लगता है उससे बहुत कम काम है। आपके मॉक-अप को वास्तव में कुछ भी नहीं करना है, लेकिन आपके परीक्षणों के लिए अनुमानित इनपुट और आउटपुट प्रदान करना है।
आपका अपना कोई भी कोड जिसे आप परीक्षण करना चाहते हैं, वह .pde स्केच के अलावा अन्य स्रोत फ़ाइलों में मौजूद है। चिंता न करें, आपका स्केच अभी भी स्केच के बाहर कुछ स्रोत कोड के साथ संकलित करेगा। जब आप वास्तव में इसके लिए नीचे आते हैं, तो आपके कार्यक्रम के सामान्य प्रवेश बिंदु से थोड़ा अधिक स्केच फ़ाइल में परिभाषित किया जाना चाहिए।
जो कुछ भी शेष है वह वास्तविक परीक्षण लिखना है और फिर अपने पसंदीदा सी ++ कंपाइलर का उपयोग करके इसे संकलित करना है! यह शायद एक वास्तविक दुनिया उदाहरण के साथ सबसे अच्छा सचित्र है।
एक वास्तविक कामकाजी उदाहरण
मेरे एक पालतू प्रोजेक्ट को यहां कुछ सरल परीक्षण मिले हैं जो पीसी पर चलते हैं। इस उत्तर प्रस्तुत करने के लिए, मैं अभी खत्म हो जाऊंगा कि कैसे मैंने Arduino पुस्तकालय के कुछ कार्यों का मजाक उड़ाया और उन मॉक-अप का परीक्षण करने के लिए मैंने जो परीक्षण लिखे। अन्य लोगों के कोड का परीक्षण नहीं करने के बारे में मैंने जो कुछ कहा उससे पहले यह विपरीत नहीं है क्योंकि मैं वह था जिसने मॉक-अप लिखा था। मैं बहुत निश्चित होना चाहता था कि मेरे नकली-अप सही थे।
Mock_arduino.cpp का स्रोत, जिसमें कोड है जो 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);
}
जब मेरा कोड हार्डवेयर सीरियल डिवाइस पर बाइनरी डेटा लिखता है, तो मैं पठनीय आउटपुट का उत्पादन करने के लिए निम्नलिखित मॉक-अप का उपयोग करता हूं।
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;
और अंत में, वास्तविक परीक्षण कार्यक्रम:
#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();
}
यह पोस्ट काफी लंबी है, इसलिए कृपया कार्रवाई में कुछ और परीक्षण मामलों को देखने के लिए GitHub पर अपनी परियोजना देखें। मैं अपनी कार्य-प्रगति को गुरु के अलावा अन्य शाखाओं में रखता हूँ, इसलिए अतिरिक्त परीक्षणों के लिए उन शाखाओं की जाँच करें।
मैंने अपनी खुद की हल्की-फुल्की परीक्षाओं को लिखने के लिए चुना, लेकिन CppUnit जैसी अधिक मजबूत इकाई-परीक्षण रूपरेखाएँ भी उपलब्ध हैं।