Как я могу unit test код Arduino?

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

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

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

Ответ 1

В отсутствие каких-либо ранее существовавших фреймворков unit test для 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();
}

Ответ 2

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

Дело в отношении микроконтроллеров устройств/эмуляторов/тестов на основе Sim

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

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

Подумайте об этом так: даже если бы вы тестировали функциональность библиотеки 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.

Ответ 3

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

Например, я излагаю PORTA с

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

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

Как только аппаратная абстракция была протестирована, я вскоре обнаружил, что в общем случае код идет от тестовой установки к ПОС и работает в первый раз.

Update:

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

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

#define SetSegmentData(x) {PORTA = x;}

Ответ 4

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

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

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

Ответ 5

simavr - это симулятор AVR, использующий avr-gcc.

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

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

Ответ 6

Вы можете unit test в Python с моим проектом, PySimAVR. Арксон используется для создания и 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

Ответ 7

Мне не известно о какой-либо платформе, которая может проверить код Arduino.

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

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

Ответ 8

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

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

Ответ 9

Эта программа позволяет автоматизировать запуск нескольких модульных тестов 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

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

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

Ответ 11

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

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

Ответ 12

Я использую Searduino при написании кода Arduino. Searduino - это симулятор Arduino и среда разработки (Makefile, C-код...), что позволяет легко взломать C/С++ с помощью вашего любимого редактора. Вы можете импортировать эскизы Arduino и запустить их в симуляторе.

Снимок экрана Searduino 0.8: http://searduino.files.wordpress.com/2014/01/jearduino-0-8.png

Searduino 0.9 будет выпущен, и видео будет записано, как только будут проведены последние тесты.... через день или два.

Тестирование на симуляторе не следует рассматривать как реальные тесты, но это, безусловно, помогло мне найти глупые/логические ошибки (забыв сделать pinMode(xx, OUTPUT) и т.д.).

BTW: Я один из людей, которые развивают Searduino.

Ответ 13

Я построил arduino_ci для этой цели. Хотя он ограничен тестированием библиотек Arduino (а не отдельных набросков), он позволяет запускать модульные тесты либо локально, либо в системе CI (например, Travis CI или Appveyor).

Рассмотрим очень простую библиотеку в каталоге Arduino Library, называемую DoSomething, с do-something.cpp:

#include <Arduino.h>
#include "do-something.h"

int doSomething(void) {
  return 4;
};

Вы бы протестировали его следующим образом (с помощью тестового файла test/is_four.cpp или чего-то подобного):

#include <ArduinoUnitTests.h>
#include "../do-something.h"

unittest(library_does_something)
{
  assertEqual(4, doSomething());
}

unittest_main()  // this is a macro for main().  just go with it.

Все это. Если этот синтаксис assertEqual и структура теста выглядят знакомо, то это потому, что я принял часть библиотеки Мэтью Мердока ArduinoUnit, на которую он ссылался в своем ответе.

См. Reference.md для получения дополнительной информации о модульном тестировании выводов ввода/вывода, синхронизации, последовательных портов и т.д.

Эти модульные тесты компилируются и запускаются с использованием скрипта, содержащегося в геме ruby. Для примеров того, как установить это, посмотрите README.md или просто скопируйте из одного из этих примеров:

Ответ 14

Существует проект под названием ncore, который предоставляет родное ядро ​​для Arduino. И позволяет вам писать тесты для кода Arduino.

Из описания проекта

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

Также в разделе "что мне нужно использовать"

Если вы хотите построить тесты, вам понадобится cxxtest от http://cxxtest.tigris.org. NCORE был протестирован с помощью cxxtest 3.10.1.

Ответ 15

Если вы хотите выполнить модульный код вне MCU (на рабочем столе), проверьте libcheck: https://libcheck.github.io/check/

Я использовал его для проверки собственного встроенного кода несколько раз. Это довольно надежная инфраструктура.

Ответ 16

Вы можете использовать emulare - вы можете перетащить микроконтроллер на диаграмму и запустить свой код в Eclipse. Документация на веб-сайте сообщает вам, как ее настроить.

Ответ 17

Попробуйте симулятор схемы Autodesk. Это позволяет тестировать код и схемы Arduino со многими другими аппаратными компонентами.

Ответ 18

Используйте Proteus VSM с библиотекой Arduino, чтобы отлаживать ваш код или тестировать его.

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

Ответ 19

В основном Arduino написан на C и C++, даже библиотеки Arduino написаны на C и C++. Итак, в простых терминах просто обработайте код как C и C++ и попробуйте выполнить модульное тестирование. Здесь под словом "дескриптор" я подразумеваю, чтобы вы изменили весь основной синтаксис, такой как serial.println, на sysout, pinmode на varaibles, void loop to while(), который прерывается либо в keystock, либо после некоторой итерации.

Я знаю, что это немного долгий процесс, и он не так прост. На моем личном опыте, как только вы это сделаете, это окажется более надежным.

-Nandha_Frost

Ответ 20

Если вы заинтересованы в запуске эскиза INO и проверке последовательного вывода, у меня есть рабочая реализация этого в моем проекте Arduino NMEA с контрольной суммой.

Следующий скрипт берет файл и использует Arduino CLI для компиляции его в HEX файл, который затем загружается в SimAVR, который оценивает его и печатает последовательный вывод. Поскольку все программы Arduino работают вечно, и у них нет возможности убить себя (exit(0) не работает), я позволил эскизу поработать несколько секунд, а затем показал полученный результат с ожидаемым результатом.

Загрузите и извлеките Arduino CLI (в данном случае версия 0.5.0 - последняя на момент написания):

curl -L https://github.com/arduino/arduino-cli/releases/download/0.5.0/arduino-cli_0.5.0_Linux_64bit.tar.gz -o arduino-cli.tar.gz
tar -xvzf arduino-cli.tar.gz

Теперь вы можете обновить индекс и установить соответствующее ядро:

./arduino-cli core update-index
./arduino-cli core install arduino:avr

Предполагая, что ваш эскиз назван nmea-checksum.ino, чтобы получить ELF и HEX, запустите:

./arduino-cli compile -b arduino:avr:uno nmea-checksum.ino

Далее, SimAVR для запуска HEX (или ELF) - я строю из исходного кода, потому что последний выпуск не работал для меня:

sudo apt-get update
sudo apt-get install -y build-essential libelf-dev avr-libc gcc-avr freeglut3-dev libncurses5-dev pkg-config
git clone https://github.com/buserror/simavr.git
cd simavr
make

Успешная компиляция даст вам simavr/run_avr, который вы можете использовать для запуска скетча. Как я уже сказал, timeout иначе он никогда не прекратится:

cd simavr
timeout 10 ./run_avr -m atmega168 -f 16000000 ../../nmea-checksum.ino.arduino.avr.uno.elf &> nmea-checksum.ino.clog || true

Сгенерированный файл будет содержать управляющие символы кода цвета ANSI, заключающие последовательный вывод, чтобы избавиться от них:

cat nmea-checksum.ino.clog | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" > nmea-checksum.ino.log
cat nmea-checksum.ino.log

Теперь все, что вам нужно сделать, это сравнить этот файл с известным хорошим файлом:

diff nmea-checksum.ino.log ../../nmea-checksum.ino.test

Если нет различий, diff завершит работу с кодом 0, в противном случае сценарий завершится ошибкой.