У нас есть большое мультиплатформенное приложение, написанное на языке C. (с небольшим, но растущим количеством C ++). В течение многих лет оно развивалось со многими функциями, которые можно ожидать в больших приложениях на C / C ++:
#ifdef
ад
- Большие файлы, затрудняющие выделение тестируемого кода
- Функции, которые слишком сложны, чтобы их можно было легко проверить
Поскольку этот код предназначен для встраиваемых устройств, выполнение его на реальной цели сопряжено с большими трудностями. Поэтому мы хотели бы проводить больше наших разработок и испытаний в быстрых циклах в локальной системе. Но мы хотели бы избежать классической стратегии «скопировать / вставить в файл .c в вашей системе, исправить ошибки, скопировать / вставить обратно». Если разработчики собираются пойти на это, мы хотели бы иметь возможность воссоздать те же тесты позже и запускать в автоматическом режиме.
Вот наша проблема: чтобы сделать код более модульным, нам нужно, чтобы он был более тестируемым. Но чтобы внедрить автоматизированные модульные тесты, нам нужно, чтобы они были более модульными.
Одна проблема состоит в том, что, поскольку наши файлы настолько велики, у нас может быть функция внутри файла, которая вызывает функцию в том же файле , которую нам нужно заглушить, чтобы сделать хороший модульный тест. Кажется, что это будет меньше проблем, так как наш код становится более модульным, но до этого еще далеко.
Мы подумали о том, чтобы пометить исходный код «известен как тестируемый» комментариями. Затем мы могли бы написать сценарий сканирования исходных файлов для тестируемого кода, скомпилировать его в отдельный файл и связать с модульными тестами. Мы могли бы постепенно вводить юнит-тесты, исправляя дефекты и добавляя больше функциональности.
Однако существует опасение, что поддержание этой схемы (вместе со всеми необходимыми функциями-заглушками) станет слишком большой проблемой, и разработчики перестанут поддерживать модульные тесты. Таким образом, другой подход заключается в использовании инструмента, который автоматически генерирует заглушки для всего кода, и связывает файл с этим. (единственный инструмент, который мы нашли для этого - это дорогой коммерческий продукт) Но, похоже, требует , чтобы весь наш код был более модульным, прежде чем мы сможем даже начать, так как только внешние вызовы могут быть заглушены из.
Лично я бы предпочел, чтобы разработчики подумали об их внешних зависимостях и разумно написали свои собственные заглушки. Но это может быть ошеломляющим, чтобы заглушить все зависимости для ужасно заросшего файла из 10000 строк. Может быть трудно убедить разработчиков, что им нужно поддерживать заглушки для всех своих внешних зависимостей, но так ли это правильно? (Еще один аргумент, который я слышал, заключается в том, что сопровождающий подсистемы должен поддерживать заглушки для своей подсистемы. Но мне интересно, приведет ли "принуждение" разработчиков к написанию своих заглушек к лучшему модульному тестированию?)
#ifdefs
, конечно, добавляет еще одно целое измерение к проблеме.
Мы рассмотрели несколько основ модульных тестов на основе C / C ++, и есть много вариантов, которые выглядят хорошо. Но мы не нашли ничего, что могло бы облегчить переход от «шарика кода без юнит-тестов» к «юнит-тестируемому коду».
Итак, вот мои вопросы ко всем, кто прошел через это:
- Что является хорошей отправной точкой? Мы идем в правильном направлении, или мы упускаем что-то очевидное?
- Какие инструменты могут быть полезны, чтобы помочь с переходом? (желательно бесплатный / открытый исходный код, поскольку наш бюджет сейчас примерно равен «нулю»)
Обратите внимание, что наша среда сборки основана на Linux / UNIX, поэтому мы не можем использовать инструменты только для Windows.