
А именно, мы будем добавлять отличную систему Сeedling. Данная система содержит в себе сразу два инструмента – Unity – непосредственно для проведения и написания тестов и CMock для генерации объектов-заглушек. Но самая большая заслуга данного пакета – простота во всех аспектах – начиная от генерации тестируемых модулей и до релиза проекта. Использование Сeedling превращает рутинное TDD (Разработка через тестирование) или TLD(если захочется так) в обычный рабочий процесс.
Как именно использовать данные инструменты:
- Свежее переиздание Test Driven Development for Embedded C (Pragmatic Programmers) от James W. Grenning
- Немного устаревшая(Ceedling уже не генерирует rake в тестируемом проекте и некоторые команды изменились), но все еще хорошая статья от Dmitry Frank https://dmitryfrank.com/articles/unit_testing_embedded_c_applications
- Конечно же, GIT разработчиков https://github.com/ThrowTheSwitch. Там найдется самая всеобъемлющая информация по использованию их инструментов, например, CMock, Ceedling.
Ну, и конечно, когда-то я соберусь с силами написать небольшую заметку
Предположим, что уже знакомы с Ceedling и нужно лишь его как-то прикрутить к нашим проектам, желательно, чтобы тесты запускались сами при старте сборки.
http://www.electronvector.com/blog/add-unit-tests-to-your-current-project-with-ceedling
Как инициализировать тестирование в уже существующем проекте
Настройка окружения
Терминал
У Eclipse, на базе которой построен STM32CubeIDE, есть сложность с вызовом терминала в рабочей директории – он может открыть терминал, но он будет в папке с установленным STM32CubeIDE. Для удобства советую установить TM Terminal (А лучше работать в VSCode, где уже терминал поддерживается, а IDE использовать для генерации и построения исходников)


Он позволяет вызвать терминал в любой папке.
Инициализация
Для примера буду показывать на тестовом проекте, который назван programel_prj. Для инициализации системы тестирования введем следующие команды в открывшимся терминале
E:\programel_prj>cd ../ E:\>ceedling new programel_prj Welcome to Ceedling! create programel_prj/project.yml Project 'programel_prj' created! - Execute 'ceedling help' from programel_prj to view available test & build task s
Здесь мы переходим выше на уровень и вводим имя проекта идентичное созданному проекту. Это можно делать и в проектах, которые уже созданы были ранее.
Был создан файл project.yml и папка src. Папку src можно удалить. Если файлы не отобразились в окне с проектом можно обновить через F5.
Правка автогенератора
После инициализации проекта Ceedling, стоит произвести некоторые изменения в файле project.yml. Зачем? (Предположим, что инициализация проекта производится с помощью кодогенератора)
Структура проекта в STM32CubeIDE генерируется сама. После завершения настройки пинов, интерфейсов и т.д. в *.ioc-файле следует запуск кодогенератора. После чего будет произведено построение проекта с определенной структурой. Мы же хотим применить TDD подход при разработке новых модулей в проекте. Удобно, если сам Ceedling будет создавать заголовочные файлы и исходники в нужных местах.
В первую очередь добавим следующее в project.yml после секции с :project::
:project: :use_exceptions: FALSE :use_test_preprocessor: TRUE :use_auxiliary_dependencies: TRUE :build_root: build # :release_build: TRUE :test_file_prefix: test_ :which_ceedling: gem :ceedling_version: 0.31.1 :default_tasks: - test:all :module_generator: :project_root: ./ :source_root: Core/Src/ :inc_root: Core/Inc/ :test_root: test/
Значит, мы добавили :module_generator: в котором определили где именно будут создаваться новые файлы модуля. Можно и название у папки test сменить, но меня это название устроило. Необходимо сообщить об этом и в секции :paths:
:paths: :test: - +:test/** - -:test/support :source: - Core/Inc/** - Core/Src/**
(Необязательно) В секции :cmock: с добавим дополнительный заголовочный файл с определением стандартных типов (uint8_t, int32_fast_t и т.д.)
:cmock: :mock_prefix: mock_ :when_no_prototypes: :warn :enforce_strict_ordering: TRUE :plugins: - :ignore - :callback :treat_as: uint8: HEX8 uint16: HEX16 uint32: UINT32 int8: INT8 bool: UINT8 :includes: - <stdint.h>
Создание модуля
Создадим модуль module_sample. Для этого введем в TM Terminal следующее:
E:\programel_prj>ceedling module:create[module_sample] File Core/Src/module_sample.c created File Core/Inc/module_sample.h created File test/test_module_sample.c created Generate Complete
Отлично, все файлы создались в нужных местах!

Прям как настоящее TDD!

В сгенерированных файлах весь код инактивирован проверкой определенного макроса. Чтобы это исправить – в настройках сборки, например, Debug определим макрос TEST.

И ещё – добавим заголовочный файл от Unity(unity.h) в папку Inc. Это позволит нам использовать автодополнение при написании непосредственно самих тестов. Данный файл у меня располагается по следующему адресу – E:\Ruby30-x64\lib\ruby\gems\3.0.0\gems\ceedling-0.31.1\vendor\unity\src\
Автоматический прогон тестов при сборке
Чтобы тестирование прогонялось автоматически при каждой сборке – нужно добавить пару комманд в build steps. Все команды в мэйкфайлах выполняться в папках Debug или Relase – в зависимости от выбранной целевой сборки. Чтобы выполнить тестирование – нужно перейти выше по каталогу (в основную папку с проектом) и выполнить команду ceedling. Для добавления пользовательских команд, которые должны быть выполнены до или после сборки есть специальные поля ввода – pre/post build steps. Команды можно объединять в цепочки через специальные знаки (см. Chaining Commands в поисковике).
Мне было бы удобнее в post-build, но в моей версии STM32CubeIDE встроены специфичные генераторы make-файлов. Они форматируют строку post-build, всегда разделяя команды друг от друга. У меня не одного такие проблемы возникли – об этой гадости подробнее тут:
Eclipse Community Forums: C / C++ IDE (CDT) » Post-Build Step
https://www.eclipse.org/forums/index.php/t/58614/
cd ../; ceedling test;

В файле test_module_sample.c теперь все хорошо и весь необходимый синтаксис корректно подсвечивается. Изменений вносить в файл не будем, оставим как есть – один игнорируемый тест.

Запустим сборку Debug версии

Что мы видим в окне Console:
15:59:53 **** Build of configuration Debug for project programel_prj **** make -j12 all cd ../; ceedling test; Test 'test_module_sample.c' --------------------------- Generating runner for test_module_sample.c... Compiling test_module_sample_runner.c... Compiling test_module_sample.c... Compiling unity.c... Compiling module_sample.c... Compiling cmock.c... Linking test_module_sample.out... Running test_module_sample.out... -------------------- IGNORED TEST SUMMARY -------------------- [test_module_sample.c] Test: test_module_sample_NeedToImplement At line (17): "Need to Implement module_sample" -------------------- OVERALL TEST SUMMARY -------------------- TESTED: 1 PASSED: 0 FAILED: 0 IGNORED: 1 arm-none-eabi-gcc "../Drivers/STM32F0xx_HAL_D..............
Отлично! Выполнился(был проигнорирован) один тест. Мы прикрутили тестирование к нашему проекту, теперь можно достаточно удобно пользоваться инструментом тестирования при разработке своих проектов в STM32CubeIDE
Comment