Разработка конечных автоматов с помощью разработки через тестирование
Поскольку модели конечных автоматов широко используются во встроенных системах, в этой статье исследуется несколько стратегий разработки программного обеспечения конечных автоматов (SM) в рамках подхода разработки через тестирование (TDD). Эта публикация начинается с объяснения основных концепций конечного автомата и техники TDD. Наконец, в нем представлены простые и упорядоченные методы разработки программного обеспечения конечного автомата, написанного на C, с использованием подхода TDD.
Модель SM состоит из состояний, переходов и действий. В то время как состояние является условием системы или элемента, переход - это путь от одного состояния к другому, обычно инициируемый интересующим событием, которое связывает предшествующее (исходное) состояние с последующим (целевым) состоянием. Фактическое поведение, выполняемое элементом, представлено в действиях.
В конечном автомате UML действия могут быть связаны с входом в состояние, выходом из состояния, переходом как таковым или тем, что называется «внутренним переходом» или «реакцией». Все формализмы конечного автомата (включая конечные автоматы UML) универсально предполагают, что конечный автомат завершает обработку каждого события, прежде чем он сможет начать обработку следующего. Эта модель исполнения называется Run To Completion (RTC). В этой модели для действий может потребоваться время, но любые ожидающие события должны ждать, пока конечный автомат не будет завершен, включая все действие выхода, действие перехода и последовательность действий входа в этом порядке.
Прежде чем рассматривать стратегии разработки конечных автоматов с использованием TDD, стоит упомянуть его определение, важность и применение.
Прежде всего, TDD - это метод постепенного создания программного обеспечения. Проще говоря, производственный код не создается без предварительного написания отказавшего модульного теста. Тесты небольшие. Тесты автоматизированы. Тест-драйв логичен, т.е. вместо того, чтобы углубляться в производственный код (оставляя тестирование на потом), практик TDD выражает желаемое поведение кода в тесте. Как только тест не проходит, специалист по TDD пишет код, и тест проходит. В основе процесса TDD лежит повторяющийся цикл, состоящий из коротких шагов, известный как «микроциклы TDD».
Шаги цикла TDD в следующем списке основаны на книге Джеймса Греннинга «Test-Driven Development for Embedded C»:
- Добавьте небольшой тест.
- Запустите все тесты, и если новый выйдет из строя, он может даже не скомпилироваться.
- Внесите небольшие изменения, необходимые для прохождения теста.
- Запустите все тесты и убедитесь, что новый проходит.
- Выполните рефакторинг, чтобы удалить дублирование и улучшить выразительность.
Давайте воспользуемся диаграммой на рисунке 1, чтобы найти более простой способ разработки конечного автомата с использованием TDD. Когда конечный автомат инициализируется, он запускается с StateA государство. Как только он получит Альфа событие, конечный автомат переходит в состояние StateB состояние, выполнив действия xStateA (), effect () и nStateB () в указанном порядке. Итак, как можно протестировать SM на Рисунке 1, чтобы определить, ведет ли он себя должным образом?
Рис. 1. Базовый конечный автомат (Источник:VortexMakes)
Самый традиционный и самый простой способ тестирования SM, показанный на рисунке 1, состоит в основном в проверке таблицы переходов состояний SMUT (тестируемого конечного автомата). Это делает тестовым примером для каждого состояния , в котором SMUT стимулируется интересующими событиями, чтобы проверить, какие переходы запускаются. В то же время это будет подразумевать проверку целевого состояния и выполненных действий для каждого запущенного перехода. Если действие достаточно сложное, для этого удобнее создать конкретный тестовый пример. (В статье «Тестирование конечных автоматов с помощью модульного теста» эта стратегия подробно объясняется).
Каждый тестовый пример разделен на четыре отдельных этапа в соответствии с шаблонами xUnit:
- Настройка устанавливает предварительные условия теста, такие как текущее состояние SM ( StateA ), событие, которое нужно обработать ( Альфа ) и ожидаемые результаты теста, которые являются целевым состоянием перехода ( StateB ) и отсортированный список действий, которые необходимо выполнить (xStateA (), effect () и nStateB ()).
- Упражнение стимулирует конечный автомат с помощью Alpha событие.
- Подтвердить проверяет полученные результаты.
- Очистка возвращает тестируемый конечный автомат в исходное состояние после теста. Это необязательно.
Упомянутой выше стратегии достаточно для разработки SM с использованием TDD. Однако в некоторых случаях для проверки работоспособности требуется более одного перехода. Это связано с тем, что эффект становится видимым только благодаря цепочке действий последующих переходов, что означает, что функциональность включает набор состояний, событий и переходов SMUT. В этих случаях более целесообразно тестировать полный и функциональный сценарий, чем отдельные переходы между состояниями. В результате тестовые примеры более функциональны и менее абстрактны, чем упомянутые ранее стратегии.
Давайте воспользуемся конечным автоматом на рисунке 2, чтобы изучить эту концепцию.
Рис. 2. Конечный автомат DoWhile (Источник:VortexMakes)
На рисунке 2 показан конечный автомат DoWhile, который моделирует цикл выполнения, аналогичный циклу «do-while». DoWhile был нарисован с помощью инструмента Yakindu Statechart Tool. Действия «x =0» и «output =0» вызываются при создании DoWhile, и эти действия устанавливают значение по умолчанию для всех атрибутов DoWhile. Количество итераций цикла должно быть установлено через «x ++» или «x =(x> 0)? x–:x ’действия. Действие «i =0» устанавливает начальные условия для цикла. Тело цикла выполняется действием «i ++», которое поддерживает итерации цикла, затем условие завершения оценивается псевдосостоянием выбора через защиту «i ==x». Если это правда, тело цикла вычисляется снова и так далее. Когда условие завершения становится ложным, цикл завершается выполнением действия «output =i».
Перед разработкой новых функций полезно создать список тестов. Список тестов основан на спецификации и определяет наилучшее видение того, что должно быть сделано. Поскольку он не обязательно должен быть идеальным, первый список - это всего лишь временный документ, который можно будет изменить позже. Первоначальный список тестов для DoWhile показан ниже:
- Все данные устанавливаются по умолчанию после инициализации SM
- Увеличить атрибут X
- Уменьшить атрибут X
- Может быть выполнен один итерационный цикл.
- Может быть выполнен цикл с несколькими итерациями.
- Может быть выполнен цикл без итераций.
- Проверить значения, выходящие за границы.
Для разработки конечного автомата DoWhile Ceedling и Unity будут использоваться вместе с наиболее простой, но понятной техникой программирования:с использованием предложений типа switch-case. Ceedling - это система сборки для создания всей среды тестирования и сборки для проекта C; Unity - это легкая портативная и выразительная тестовая программа на языке C для проектов C.
Этот конечный автомат представляют два файла, DoWhile.h и DoWhile.c, так что они представляют собой тестируемый исходный код. В листинге 1 показан фрагмент файла test_DoWhile.c, который реализует приведенный выше список тестов, применяя ранее упомянутую стратегию. Для упрощения этой статьи в листинге кода 1 показан только тестовый пример:«Может быть выполнен один цикл итерации», который реализуется с помощью test_SingleIteration (). Код и модель доступны в https://github.com/leanfrancucci/sm-tdd.git репозитории.
Листинг 1:тест с одной итерацией (Источник:VortexMakes)
Этот тест проверяет, что DoWhile может правильно выполнить только одну итерацию. Для этого test_SingleIteration () инициализирует конечный автомат DoWhile, вызывая DoWhile_init () (строка 96). Он устанавливает номер итерации для нуля, который будет выполняться циклом DoWhile. После этого DoWhile готов обрабатывать события, вызывая DoWhile_dispatch (). Чтобы выполнить одну итерацию, test_SingleIteration () отправляет Up событие для DoWhile (строка 97). Это событие увеличивает номер итерации до единицы. Тест запускает цикл, отправляя Старт событие (строка 98), затем он отправляет Альфа событие, поэтому DoWhile выполняет одну итерацию (строка 99). Это проверяется проверкой того, что значение атрибута out равно количеству выполненных итераций (строка 101). Наконец, DoWhile должен оставаться в StateC состояние (строка 102).
Чтобы доказать, что DoWhile может выполнять более одной итерации, функция test_SingleIteration () расширена, как показано в листинге 2 кода.
Листинг 2:Тест с несколькими итерациями (Источник:VortexMakes)
Тест test_NoneIteration (), показанный в листинге 3, проверяет, что DoWhile не выполняет никаких итераций при получении Alpha событие без предварительной установки номера итерации с помощью Вверх события.
Листинг 3:Тест без итераций (Источник:VortexMakes)
Хотя детали реализации DoWhile не являются целью данной статьи, листинг кода 4 и листинг 5 показывают часть файлов DoWhile.c и DoWhile.h. Эти файлы на самом деле представляют собой наглядную реализацию DoWhile с использованием предложений «switch-case» на языке C.
Листинг 4:Фрагмент реализации DoWhile (Источник:VortexMakes)
Листинг 5:Фрагмент спецификации DoWhile (Источник:VortexMakes)
Обе стратегии, представленные выше, предоставляют простые и упорядоченные методы разработки программного обеспечения конечного автомата с использованием TDD - одного из наиболее важных подходов к повышению качества программного обеспечения.
Первая стратегия состоит в основном из проверки таблицы переходов состояний SMUT. Этот метод создает тестовый пример для каждого состояния . Другая стратегия предлагает реализовать тестовый пример для полного и функционального сценария , который часто включает в себя набор состояний, событий и действий SMUT. Эта вторая стратегия делает тест более функциональным и менее абстрактным, чем первый. Хотя эти стратегии не зависят от конкретного типа системы, языка программирования или инструмента, они очень полезны во встроенных системах, поскольку многие из них имеют поведение на основе состояний, которое обычно определяется в одном или нескольких конечных автоматах.
Язык C был выбран потому, что это один из самых популярных языков для разработки встроенного программного обеспечения. Итак, чтобы применить TDD на этом языке, были выбраны Ceedling и Unity. В заключение, эти методы определенно позволяют разработчикам более простым и упорядоченным образом создавать гораздо более гибкое, поддерживаемое и многократно используемое программное обеспечение, чем традиционные подходы.
Встроенный
- Обычные проблемы со станками с ЧПУ
- Ваши знания о производстве на вертикальных фрезерных станках
- Фрезерные инструменты в сочетании с станками с ЧПУ повышают надежность
- Маленькие машины с большим технологическим портфелем
- Как избежать проблем с бывшими в употреблении станками с ЧПУ
- Эволюция автоматизации тестирования с помощью искусственного интеллекта
- Запуск проектов с нуля с помощью аутсорсинга
- Состояние производства в 2021 году – часть 2 – с Make UK
- Всегда гладкая поверхность с шлифовальными станками Okamoto
- Что можно сделать на станке с ЧПУ?