Как я могу тестировать код Arduino? - PullRequest
158 голосов
/ 23 апреля 2009

Я хотел бы иметь возможность модульного тестирования моего кода Arduino. В идеале я мог бы запускать любые тесты без необходимости загружать код в Arduino. Какие инструменты или библиотеки могут помочь мне с этим?

В разработке находится эмулятор Arduino , который может быть полезен, но пока еще не готов к использованию.

AVR Studio от Atmel содержит симулятор чипа, который может быть полезен, но я не понимаю, как бы я использовал его в сочетании с Arduino IDE.

Ответы [ 19 ]

114 голосов
/ 11 июля 2012

Не запускать юнит-тесты на устройстве Arduino или эмуляторе

Дело против микроконтроллера Устройства / Эмулятор / Сим-тесты

Существует много дискуссий о том, что означает модульный тест , а я нет действительно пытаюсь спорить об этом здесь. Этот пост не говорю вам избегать всех практических испытаний вашей конечной цели аппаратное обеспечение. Я пытаюсь сделать вывод об оптимизации вашего цикл обратной связи разработки, устраняя целевое оборудование от ваши самые обыденные и частые тесты. Предполагаемые единицы измерения быть намного меньше, чем весь проект.

Целью модульного тестирования является проверка качества вашего собственного кода. Модульные тесты, как правило, никогда не должны проверять функциональность факторов, находящихся вне вашего контроля.

Подумайте об этом так: даже если бы вы тестировали функциональность библиотеки Arduino, аппаратного обеспечения микроконтроллера или эмулятора, абсолютно невозможно , чтобы результаты такого теста могли рассказать вам о качестве вашей собственной работы. Следовательно, гораздо полезнее и эффективнее писать модульные тесты, которые не запускаются на целевом устройстве (или эмуляторе).

Частое тестирование на целевом оборудовании имеет мучительно медленный цикл:

  1. Настройте свой код
  2. Компиляция и загрузка на устройство Arduino
  3. Наблюдайте за поведением и угадывайте, делает ли ваш код то, что вы ожидаете
  4. Повторите

Шаг 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.

60 голосов
/ 27 апреля 2009

В отсутствие каких-либо ранее существующих структур для модульного тестирования для Arduino я создал ArduinoUnit . Вот простой эскиз Arduino, демонстрирующий его использование:

#include <ArduinoUnit.h>

// Create test suite
TestSuite suite;

void setup() {
    Serial.begin(9600);    
}

// Create a test called 'addition' in the test suite
test(addition) {
    assertEquals(3, 1 + 2);
}

void loop() {
    // Run test suite, printing results to the serial port
    suite.run();
}
21 голосов
/ 23 апреля 2009

У меня есть значительный успех, когда я тестирую свой код PIC, абстрагируясь от аппаратного доступа и проверяя его в своих тестах.

Например, я абстрагирую PORTA с помощью

#define SetPortA(v) {PORTA = v;}

Тогда SetPortA можно легко смоделировать, не добавляя служебный код в версии PIC.

Как только аппаратная абстракция была протестирована, я вскоре обнаружил, что, как правило, код переходит с испытательного стенда на PIC и работает впервые.

Обновление:

Я использую шов #include для кода модуля, # включая код модуля в файле C ++ для тестового стенда и файл C для целевого кода.

В качестве примера я хочу мультиплексировать четыре 7-сегментных дисплея, один порт управляет сегментами, а второй выбирает дисплей. Код дисплея взаимодействует с дисплеями через SetSegmentData(char) и SetDisplay(char). Я могу смоделировать их на своем тестовом стенде C ++ и проверить, получаю ли я ожидаемые данные. Для цели я использую #define, чтобы получить прямое назначение без издержек на вызов функции

#define SetSegmentData(x) {PORTA = x;}
15 голосов
/ 21 ноября 2009

Кажется, что emulino отлично справится с работой.

Emulino - эмулятор для платформы Arduino Грега Хьюгилла. ( Источник )

GitHub репозиторий

11 голосов
/ 01 февраля 2010

simavr - это симулятор AVR с использованием avr-gcc.

Он уже поддерживает несколько микроконтроллеров ATTiny и ATMega, и, по словам автора, легко добавить еще несколько.

В примерах лежит simduino, эмулятор Arduino. Он поддерживает запуск загрузчика Arduino и может быть запрограммирован с помощью avrdude через Socat (модифицированный Netcat ).

8 голосов
/ 24 октября 2011

Вы можете выполнить модульное тестирование на Python с моим проектом, PySimAVR . Arscons используется для построения и simavr для моделирования.

Пример:

from pysimavr.sim import ArduinoSim    
def test_atmega88():
    mcu = 'atmega88'
    snippet = 'Serial.print("hello");'

    output = ArduinoSim(snippet=snippet, mcu=mcu, timespan=0.01).get_serial()
    assert output == 'hello'

Стартовый тест:

$ nosetests pysimavr/examples/test_example.py
pysimavr.examples.test_example.test_atmega88 ... ok
6 голосов
/ 11 января 2013

Эта программа позволяет автоматически запускать несколько юнит-тестов Arduino. Процесс тестирования запускается на ПК, но тесты выполняются на реальном оборудовании Arduino. Один набор модульных тестов обычно используется для тестирования одной библиотеки Arduino. (это

Форум Arduino: http://arduino.cc/forum/index.php?topic=140027.0

Страница проекта GitHub: http://jeroendoggen.github.com/Arduino-TestSuite

Страница в индексе пакетов Python: http://pypi.python.org/pypi/arduino_testsuite

Юнит-тесты написаны с помощью "Библиотеки юнит-тестирования Arduino": http://code.google.com/p/arduinounit

Для каждого набора юнит-тестов выполняются следующие шаги:

  • Прочтите файл конфигурации, чтобы узнать, какие тесты нужно запустить
  • Скрипт компилирует и загружает эскиз Arduino, содержащий код модульного тестирования.
  • Модульные тесты выполняются на плате Arduino.
  • Результаты теста распечатываются через последовательный порт и анализируются скриптом Python.
  • Сценарий запускает следующий тест, повторяя вышеуказанные шаги для всех тестов, которые запрашиваются в файле конфигурации.
  • Сценарий выводит сводную информацию о всех неудачных / пройденных тестах в полном комплекте тестов.
6 голосов
/ 04 октября 2010

Мы используем платы Arduino для сбора данных в большом научном эксперименте. Впоследствии мы должны поддерживать несколько плат Arduino с разными реализациями. Я написал утилиты Python для динамической загрузки шестнадцатеричных изображений Arduino во время модульного тестирования. Код, найденный по ссылке ниже, поддерживает Windows и Mac OS X через файл конфигурации. Чтобы узнать, где ваши шестнадцатеричные изображения размещены с помощью IDE Arduino, нажмите клавишу Shift, прежде чем нажать кнопку сборки (воспроизведения). Нажмите клавишу Shift во время загрузки, чтобы узнать, где находится ваша avrdude (утилита загрузки из командной строки) в вашей системе / версии Arduino. Кроме того, вы можете посмотреть прилагаемые файлы конфигурации и использовать место установки (в настоящее время на Arduino 0020).

http://github.com/toddstavish/Python-Arduino-Unit-Testing

6 голосов
/ 23 апреля 2009

Я не знаю ни одной платформы, которая может тестировать код Arduino.

Однако есть платформа Fritzing , которую вы можете использовать для моделирования оборудования, а затем для экспорта диаграмм печатных плат и прочего.

Стоит проверить.

5 голосов
/ 24 октября 2011

Храните аппаратный код отдельно или абстрагировано от остальных, чтобы вы могли тестировать и отлаживать этот больший «отдых» на любой платформе, для которой у вас есть хорошие инструменты и с которой вы больше всего знакомы.

По сути, постарайтесь собрать как можно больше окончательного кода из максимально возможного количества известных строительных блоков. Остальная аппаратно-зависимая работа будет намного проще и быстрее. Вы можете закончить это, используя существующие эмуляторы и / или эмулирующие устройства самостоятельно. И тогда, конечно, вам нужно как-то проверить реальную вещь. В зависимости от обстоятельств, это может или не может быть очень хорошо автоматизировано (то есть кто или что будет нажимать кнопки и предоставлять другие входные данные? Кто или что будет наблюдать и интерпретировать различные индикаторы и выходные данные?).

...