Лучшая практика при модульном тестировании для встроенной разработки

45

Я ищу некоторые передовые стратегии для кода модульного тестирования, написанного для встроенной системы. Под встроенной системой я подразумеваю код, такой как драйверы устройств, обработчики ISR и т. Д., Вещи, которые очень близки к металлу.

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

Обновить

Я наткнулся на фреймворк для тестирования на Си, который, похоже, довольно успешно тестирует встроенные проекты. Он использует идеи насмешливого оборудования. Проверьте Unity , CMock и, возможно, Ceedling .

Обновление 06 июля 2016

Наткнулся на cmocka - похоже, более активно работал над.

tehnyit
источник
1
В аналогичных обстоятельствах мы отправились за Cmocka
Mawg
Я написал очень подробное руководство по теме: модульное тестирование встроенных приложений на C с помощью Ceedling
Дмитрий Франк

Ответы:

28

Я хотел бы абстрагироваться от аппаратных зависимостей на самом раннем этапе и построить систему на основе программной эмуляции / тестирования, обеспечивающих всевозможные тестовые среды. Часто мой ПК для разработки использовался для тестирования целых 95% или более всей системы. Стоимость дополнительных издержек (еще один уровень абстракции) была легко компенсирована более чистым кодом, сгенерированным в результате этой абстракции.

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

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

mattnz
источник
Это в сочетании с ответом Джонатана Клайна Иееи является успешной стратегией. Используйте абстракцию, чтобы сделать большую часть кода тестируемой, и с помощью простой тестовой среды протестируйте не абстрагируемые биты на реальном оборудовании. Я лично видел эту работу с несколькими платформами.
Тим Виллискрофт
3
Каждый продукт, который мы производим, имеет уровень аппаратной абстракции с реализацией драйверов для целевой платформы и ПК. Это позволяет нам легко запускать юнит-тесты. Другие преимущества: мы также можем проводить быстрые системные тесты и разрабатывать большую часть программного обеспечения без какого-либо оборудования (как это будет доступно позже).
MaR
15

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

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

Используя TeraTerm в качестве инжектора сигналов последовательного порта и написание некоторых макросов TeraTerm (занимает около 20 минут), существует огромный набор автоматических тестов, которые можно запускать на любой части встроенной системы - будь то уровень драйвера, O / S, слой 4-5 и т. д. TeraTerm: http://en.sourceforge.jp/projects/ttssh2/

Если последовательный порт недоступен во встроенной системе, используйте аппаратный инструмент для преобразования данных через USB / последовательный порт в цифровые сигналы (также недорогие и легко доступные ). Когда вы читаете это, я использую плату микроконтроллера за 30 долларов США (UBW: http://www.schmalzhaus.com/UBW32/ ) для тестирования встроенной системы для производства, вводя стимул с помощью макросов TeraTerm, который отправляется через USB / serial на микроконтроллер, который выполняет модифицированную прошивку, которая осуществляет цифровые входы и контролирует цифровые выходы целевой встроенной системы. В связи с этим мы разработали скрипт на python (использует pyserial и pexpect) для автоматизации ввода и проверки данных. Ничего из этого не сложно и не дорого, По моему опыту, менеджеры тратят большие деньги (например, испытательное оборудование за 30 000 долларов США), когда команда тестировщиков неопытна и не может придумать эти простые решения - к сожалению, оборудование общего назначения большого чугуна часто не включает в себя контрольные примеры которые ловят наихудший случай времени / и т. д. целевой системы. Поэтому недорогой метод предпочтительнее для тестового покрытия. Хочешь верь, хочешь нет.

Джонатан Клайн IEEE
источник
1
Что ж, я сделал дорогое заявление, работая в автомобильной промышленности, и все должно быть детерминированным, повторяемым, и для его разработки обычно требуется пара инженеров. Также, когда в цепочке испытаний используется больше элементов, обслуживание также становится проблемой. Спасибо, что сообщили нам о UBW, это выглядит как хороший вариант.
Технит
2
Только не заводите меня на LabView ... как правило, это ужасно.
Джонатан Клайн IEEE
1
Наши инженеры-испытатели любят LabView, я сам не совсем понимаю.
Технит
Это довольно близко к тому, что я делаю для различных испытаний, только я использую Python и его последовательные библиотеки. Затем я мог бы подключить свои низкоуровневые тесты к юнит-тестерам Python вместе с чем-то вроде Flask / Qt, чтобы дать легкий в использовании интерфейс.
radix07
5

Это очень сложная проблема.

На самом деле я спроектировал модуль модульного тестирования для встроенной системы, который позволял бы имитировать аппаратные события / прерывания и контролировать время выполнения (чтобы мы покрывали все возможные чередования из-за параллелизма), и потребовалась команда программисты более 2-х лет, чтобы реально реализовать это и запустить его в работу. Этот проект является частной разработкой, но похожий (более простой по дизайну) проект доступен здесь .

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

littleadv
источник
Я обнаружил, что единица измерения вручную подвержена ошибкам, обычно при создании стимула или при измерении результатов. Особенно верно, если юнит тест сложен. Если вам придется повторить модульный тест снова, он становится еще более склонным к ошибкам.
Технит
@tehnyit - да, именно поэтому мы решили разработать систему автоматизации. Иногда ничего нельзя сделать вручную, но модульное тестирование должно быть всеобъемлющим и охватывать вопросы синхронизации. Так что тогда у вас нет большого выбора, но автоматизация на этом уровне - очень дорогая вещь.
littleadv
4

Редактировать: мой ответ близок к Mattnz, я думаю ...


Я хочу связать эту проблему с другими, со всеми тестами, которые зависят от чего-то внешнего по отношению к вашему коду (например, системные часы, постоянная файловая система или база данных, связь с внешним веб-сервисом ...). Я предлагаю одинаковую политику для всех из них, изолировать два уровня в двух уровнях кода.

Тестирование одной внешней операции

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

Эти тесты:

  • должно быть настолько простым, насколько это возможно: ни алгоритма, ни условия, ни цикла
  • может зависеть от порядка и машины: вам нужно следовать строгому порядку и повторять его на каждом оборудовании
  • в основном стабильны в течение вашего проекта, поэтому вам не нужно запускать их так часто
  • так что запускать их вручную - вариант; автоматизация еще лучше, если не слишком сложная
  • Обратите внимание, что тестируется не ваш код , это инструмент, в котором нуждается ваш код ... Так что тестирование может быть необязательным для вас, оно могло быть сделано другой командой ...

Тестирование логики (кода, алгоритма), которая связывает внешние операции

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

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

KLE
источник
3

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

Если вы хотите сделать это, я бы предложил изменить QEMU. Но это было бы нелегко. Подобные вещи обычно выполняются только тогда, когда вы разрабатываете специализированный чип с микроконтроллером и некоторыми другими ядрами для ввода / вывода.

Система разработки, продаваемая ARM Holdings, обеспечивает это и, вероятно, с ней легче работать, чем взламывать QEMU, но это очень дорого.

Существует несколько эмуляторов Open Source ARM, которые запускают одну подпрограмму, которая сама может вызывать другие подпрограммы, которые вы можете использовать для отладки настройки производительности подпрограмм, которые не зависят от аппаратного доступа. Я использовал один из них с большим успехом для оптимизации шифратора AES для ARM7TDMI.

Вы можете написать простой модуль модульного тестирования на C или C ++, связать с ним тестируемый класс или подпрограмму, а затем запустить его в симуляторе.

В течение многих лет я размышлял над подобной проблемой - как выполнить модульное тестирование кода ядра Linux или Mac OS X. Это должно быть возможно, но я никогда не пробовал. Возможно, стоит создать полное ядро, а не тестировать свой код изолированно, с модульным тестовым фреймворком, напрямую связанным с вашим ядром. Затем вы запускаете юнит-тесты с какого-то внешнего интерфейса.

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

Майк Кроуфорд
источник
3

Как и в случае не встроенного TDD, фиктивные объекты , безусловно, ваш друг.

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

Кроме того, если вы не сможете проводить тестирование в режиме онлайн до тех пор, пока не опоздаете в проекте, это не означает, что вам также не следует готовить набор онлайн-тестов.

Они должны (первоначально) должны только проверить биты, которые не могли быть проверены в автономном режиме. Конечно, это не TDD (так как вы создаете тесты заранее), но ваша автономная разработка TDD должна дать вам хорошее представление о том, как должен выглядеть ваш аппаратный интерфейс и, следовательно, какие онлайн-тесты вам нужно выполнить.

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

Марк Бут
источник
+1 за перенос ложных предметов на тарелку, @mark. Одна из проблем заключается в том, что обеспечение точности макетов объектов, что означает понимание объекта, который должен быть симулирован, должно быть достаточно глубоким. Это хорошо, поскольку заставляет разработчика понимать поведение внешних объектов, с которыми он взаимодействует.
Технит
1

Во встроенной разработке вы часто выполняете граничное сканирование, чтобы убедиться, что все приложение (включая оборудование) работает. Также см. JTAG для отладки системы.

Тестирование программных подпрограмм без привязки к оборудованию может быть выполнено с помощью стандартной среды модульного тестирования C, такой как Check . Но остерегайтесь ограничений памяти (особенно стекового пространства и т. Д. На небольших устройствах). Знай свои контракты! Вы также можете попытаться абстрагировать программные подпрограммы от аппаратного обеспечения, чтобы получить больший охват тестированием, но это обычно является дорогостоящим с точки зрения производительности на встроенных устройствах, таких как небольшие PIC или AVR. Тем не менее, вы можете макетировать аппаратные порты, чтобы добиться большего охвата (и, конечно, вы можете протестировать и этот макет).

Вы также можете попробовать использовать эмуляторы для микросхем или схемных симуляторов, но эти виды инструментов дороги (особенно в сочетании) и сложны.

сокол
источник
Согласитесь с граничным сканированием и JTAG, но из-за конструкции оборудования это не всегда возможно или доступно.
Технит