Перейти к содержанию

Модульный тест (unit test)

Прошивку обычно проверяют целиком: залили, посмотрели на светодиод. Модульный тест проверяет одну функцию — разбор команды, расчёт CRC, фильтр АЦП — отдельно от остальной программы и от микроконтроллера, за доли секунды и столько раз, сколько нужно.

Обновлено Редакция GAW

Модульный тест (unit test) — автоматическая проверка одной функции или одного модуля программы в отрыве от остального кода. Тест подаёт на вход известные данные и сравнивает результат с ожидаемым; если не совпало, он сообщает, какая проверка провалилась и где. Набор таких тестов запускают после каждого изменения и сразу видят, не сломалось ли что-то.

Как выглядит на C

В фреймворке Unity, который часто используют во встраиваемых проектах, ядро — один файл .c и пара заголовков. Тестовый файл содержит:

  • setUp() и tearDown() — подготовку и уборку, которые выполняются до и после каждого теста;
  • функции-тесты с проверками вроде TEST_ASSERT_EQUAL_HEX16(0x4B37, crc);
  • main(), который вызывает UNITY_BEGIN(), затем RUN_TEST() для каждого теста и UNITY_END().

Исполняемый файл собирается из Unity, тестового файла и проверяемого модуля. Без фреймворка простейшая проверка — стандартный макрос assert.

На компьютере, а не на плате

Руководство Unity прямо говорит, что большинство разработчиков запускают модульные тесты не на целевом железе: там слишком много ограничений по памяти и скорости, нет полного контроля над регистрами, а модульные тесты не заменяют системные. Тесты собирают обычным компилятором для компьютера или запускают в симуляторе с тем же компилятором, что и прошивку. Если тесты всё-таки идут на плате, вывод результатов настраивают макросом UNITY_OUTPUT_CHAR — на UART или через semihosting.

Чтобы это работало, код делят на две части: логику, которая только считает, и тонкий слой работы с регистрами. Логику тестируют на компьютере, а зависимости от периферии подменяют тестовыми двойниками.

Что проверять

Лучшие кандидаты — функции без побочных эффектов: разбор кадров протокола, CRC, фильтры, пересчёт кодов АЦП, конечные автоматы. Эталоны для CRC берут из каталога Грега Кука: для CRC-16/MODBUS контрольное значение строки «123456789» — 0x4B37; проверить свои параметры можно в калькуляторе CRC. Как организовать тесты, сборку и подмену регистров в проекте на AVR и STM32 — в статье о модульном тестировании прошивки.

Частые вопросы

Можно ли запускать модульные тесты прошивки на компьютере?

Да, и авторы Unity советуют именно так: собирать тесты как обычную программу для компьютера или для симулятора. На плате мало памяти, нет полного контроля над регистрами, а тест получается медленнее. Для этого код, который считает и принимает решения, отделяют от кода, который пишет в регистры периферии.

Что тестировать модульными тестами в прошивке?

Всё, что зависит только от входных данных: разбор протоколов и кадров, CRC и контрольные суммы, фильтры и пересчёт отсчётов АЦП в физические величины, конечные автоматы, арифметику с фиксированной точкой. Работу с периферией изолируют за интерфейсом и подменяют тестовыми двойниками.

Где взять ожидаемые значения для теста CRC?

Из каталога параметризованных CRC Грега Кука: для каждого алгоритма там указано значение check — CRC от строки «123456789». Для CRC-16/MODBUS это 0x4B37. Тест вычисляет CRC той же строки и сравнивает с эталоном.

Источники

  1. ThrowTheSwitch. Unity Test Framework v2.7.0: docs/UnityGettingStartedGuide.md, docs/UnityConfigurationGuide.md, src/unity.h — Unity — фреймворк модульного тестирования на C; ядро — один файл .c и пара заголовков; тестовый файл содержит setUp() и tearDown(), которые выполняются до и после каждого теста; main вызывает UNITY_BEGIN(), RUN_TEST() для каждого теста и UNITY_END(); большинство разработчиков запускают тесты не на целевом железе, а как приложения для компьютера или в симуляторе — на железе слишком много ограничений, нет полного контроля над регистрами, и модульное тестирование не заменяет системное; тест собирается из Unity, тестового файла и проверяемого файла; вывод результатов настраивается макросом UNITY_OUTPUT_CHAR
  2. ISO/IEC 9899:201x (C11), Committee Draft N1570, April 2011 — разд. 7.2.1.1: макрос assert при ложном выражении выводит сведения о месте вызова и вызывает abort — стандартная проверка без фреймворка
  3. G. Cook. Catalogue of parametrised CRC algorithms with 16 bits, reveng.sourceforge.io, обновлено 11 декабря 2024 — для каждого алгоритма указано контрольное значение check — CRC строки «123456789»; например CRC-16/MODBUS — 0x4B37; такие эталоны — готовые ожидаемые значения для тестов

Нашли ошибку?