Не запускайте модульные тесты на устройстве или эмуляторе Arduino
Дело против микроконтроллеров Device / Emulator / Sim-based tests
О том, что означает unit test, идет много дискуссий, и я не пытаюсь здесь спорить об этом. Этот пост не советует вам избегать всех практических испытаний на вашем конечном целевом оборудовании. Я пытаюсь сделать акцент на оптимизации вашего цикла обратной связи при разработке, исключив ваше целевое оборудование из ваших самых рутинных и частых тестов. Предполагается, что тестируемые блоки намного меньше всего проекта.
Цель модульного тестирования - проверить качество вашего собственного кода. Модульные тесты, как правило, никогда не должны проверять функциональность факторов, находящихся вне вашего контроля.
Подумайте об этом так: даже если бы вам пришлось протестировать функциональность библиотеки Arduino, оборудования микроконтроллера или эмулятора, было бы абсолютно невозможно, чтобы такие результаты тестирования могли сказать вам что-либо о качестве вашего Наша работа. Следовательно, гораздо более ценно и эффективно писать модульные тесты, которые не запускаются на целевом устройстве (или эмуляторе).
Частое тестирование на вашем целевом оборудовании имеет мучительно медленный цикл:
- Настройте свой код
- Скомпилировать и загрузить на устройство Arduino
- Наблюдайте за поведением и угадайте, выполняет ли ваш код то, что вы ожидаете.
- Повторить
Шаг 3 особенно неприятен, если вы ожидаете получать диагностические сообщения через последовательный порт, но сам ваш проект должен использовать единственный последовательный порт вашего Arduino. Если вы думали, что библиотека SoftwareSerial может помочь, вы должны знать, что это может нарушить любую функциональность, которая требует точного времени, например, одновременное генерирование других сигналов. Эта проблема случилась со мной.
Опять же, если вы должны были протестировать свой скетч с помощью эмулятора, и ваши критичные ко времени процедуры работали безупречно до тех пор, пока вы не загрузили его на настоящую Arduino, то единственный урок, который вы усвоите, - это то, что эмулятор ошибочен - и зная это до сих пор. не раскрывает ничего о качестве вашей собственной работы.
Если глупо тестировать на устройстве или эмуляторе, что следует делать?
Вы, вероятно, используете компьютер для работы над своим проектом Arduino. Этот компьютер на порядки быстрее микроконтроллера. Напишите тесты, которые нужно собрать и запустить на вашем компьютере.
Помните, что поведение библиотеки и микроконтроллера Arduino следует считать правильным или, по крайней мере, постоянно неправильным.
Если результаты ваших тестов противоречат вашим ожиданиям, то, скорее всего, у вас есть недостаток в тестируемом коде. Если результат вашего теста соответствует вашим ожиданиям, но программа ведет себя некорректно, когда вы загружаете его в Arduino, значит, вы знаете, что ваши тесты основывались на неверных предположениях и, вероятно, у вас есть некорректный тест. В любом случае вам будет дано реальное представление о том, какими должны быть ваши следующие изменения кода. Качество вашего отзыва повышено с "что-то не работает" на "этот конкретный код не работает".
Как создавать и запускать тесты на вашем ПК
Первое, что вам нужно сделать, это определить цели тестирования. Подумайте, какие части вашего собственного кода вы хотите протестировать, а затем убедитесь, что ваша программа построена таким образом, чтобы вы могли изолировать отдельные части для тестирования.
Если части, которые вы хотите протестировать, вызывают какие-либо функции Arduino, вам нужно будет предоставить имитацию замены в вашей тестовой программе. Это намного меньше работы, чем кажется. Ваши макеты не должны ничего делать, кроме как обеспечивать предсказуемые ввод и вывод для ваших тестов.
Любой ваш собственный код, который вы собираетесь протестировать, должен существовать в исходных файлах, кроме скетча .pde. Не волнуйтесь, ваш скетч все равно будет компилироваться даже с некоторым исходным кодом за пределами скетча. Когда вы действительно приступите к делу, в файле скетча должно быть определено немного больше, чем обычная точка входа вашей программы.
Осталось только написать настоящие тесты, а затем скомпилировать их с помощью вашего любимого компилятора C ++! Вероятно, лучше всего это проиллюстрировать на примере из реальной жизни.
Реальный рабочий пример
В одном из моих любимых проектов, найденных здесь, есть несколько простых тестов, которые выполняются на ПК. Для этого ответа я просто расскажу, как я смоделировал некоторые функции библиотеки 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, чтобы увидеть еще несколько тестовых примеров в действии. Я храню свои незавершенные работы в ветвях, отличных от master, поэтому проверяйте и эти ветки на предмет дополнительных тестов.
Я решил написать свои собственные облегченные процедуры тестирования, но также доступны более надежные среды модульного тестирования, такие как CppUnit.
person
Iron Savior
schedule
11.07.2012