Pull to refresh

Comments 35

UFO just landed and posted this here
Прочитал и не понял что конкретно тестировалось.
Хотя бы привести пример десятка функций подвергавшихся тестированию и что они должны были делать.
Не ясна совокупная выгода такого подхода и контекст.

Ну, скажем, есть некий датчик, с которым нужно общаться по некоему протоколу.
Датчик физически получить на руки можно примерно через полгода, но документация на него есть.


Значит, можно писать код и тестировать его, подсовывая на вход данные, которые составлены по документации.


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


Выгода — все делается программно, не нужно писать какие-то дополнительные вспомогательные программы или разрабатывать новые платы. Плюс это хорошо автоматизируется.


Пример какой-то такой будет:


Spoiler header
    UMBA_TEST("Task should parse answer and put distance in the register")
    {
        ::umba::setTaskCycleCounter(1);

        // делаем вид, что передача уже завершена
        osSemaphoreGive( uartMock.m_transmitCompleteSem );

        // имитируем ответ от датчика с первым адресом
        // ибо первый запрос должен быть к нему
        uint16_t x = presendRndAnswer(1);

        run_task();

        UMBA_CHECK( testTable.getReg16Val( REG_RO_LS5_1_DIST_0) == x, "Distance from answer should be in the register");

        UMBA_CHECK
        (
            testTable.getRegVal( REG_RO_LS5_STATUS ) == Ls5Task::status_error,
            "Common state should be error because only one sensor has answered"
        );

        return 0;
    }

    static void presendAnswer(uint8_t adr, uint16_t data)
    {
        // шаблон ответа на запрос расстояния
        static char answer[] = {"!08LR55555\r"};
        uint8_t ansSize = sizeof(answer)-1;

        // преобразуем адрес в строку
        uint8ToAscii(adr, answer+1);

            // преобразуем данные в строку
        uint16ToAscii(data, answer+5);

        // заполним очередь
        uartMock.receiveData( answer, ansSize );

    }

    // предпослать ответ с рандомными данными
    static uint16_t presendRndAnswer(uint8_t adr)
    {
        using common_functions::xorshiftRandomByte;

        uint16_t x = xorshiftRandomByte()<<8 | xorshiftRandomByte();

        presendAnswer(adr, x);

        return x;
    }
Но это же не тестирование, а моделирование.
Причем модель датчика может быть ошибочной.
Скажем тоже работал с китайскими дешевыми лазерными лидарами.
Они могут выдать непредсказуемые строки, которые неточно приведены в документации.
Т.е. моделирование датчиков без их наличия настолько рисковано, что не вижу смысла этим заниматься.
BLDC мотор в этом плане проще моделируется.

И почему вам сложно просто накидать десяток наименований тестируемых функций если вы так широко применяете юнит-тестирование?
Или это все таки не юнит-тестирование?

Насколько я понимаю терминологию — это именно юнит-тестирование. Не интеграционное, не системное, не тестирование устройства в сборе — а тестирование отдельных программных компонентов.


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


И почему вам сложно просто накидать десяток наименований тестируемых функций если вы так широко применяете юнит-тестирование?

Я хотел привести пример, который был бы более-менее понятен сам по себе (и, собственно, привел его в предыдущем комментарии). Конечно, я могу сюда вставить огромный листинг, только что он вам скажет? Что вы хотите в нем увидеть?


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

В моем случае это был датчик с военной приемкой, поэтому документация все же была более-менее.


И потом — а что делать-то? Это ведь реальная ситуация; срок поставки — полгода, через полгода времени писать уже не будет. Писать "на шару" и не тестировать никак?

Ну все же просто — либо у вас защитное программирование во все поля (и существует доказательство безопасности, например), либо вы пишете чистые функции (я не про ФП, «чистые» — в смысле «без излишеств»), а дальше отлавливаете ошибки во время отладки и эксплуатации и покрываете конкретные участки кода конкретными тестами, чтобы те же самые ошибки больше не повторялись. Кажется глупым тестировать код на ошибку, которую только что исправили, но это на самом деле нормально, это то же самое, как системная работа над risk management file. Если вы просто ошибку исправите, то даже сам факт ее существования когда-то потонет в коммитах и тикетах.
Очеь много непонятных терминов применяете. Не из embedded.
Поэтому не вижу пока предмета обсуждения. Перечислите хотя бы вы десяток «чистых» функций.

Но поскольку автор не привел списка функций (ибо думает что никто не занимается тем же чем и он) считаю что этого списка нет. Откуда резонное подозрение — а было ли тестирование?
А то что он привел — есть иммитационное моделирования. Я всеми руками за иммитационное моделирование, но не в таком урезанном виде как у автора.
Оно должно быть гораздо обширней.
Вообще тестирование такая важная вещь что лучше его встраивать в релизный код как это и делается в отвественных системах.
ибо думает что никто не занимается тем же чем и он

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

Очеь много непонятных терминов применяете. Не из embedded.


Именно что из embedded. И что там непонятного вы увидели?

Перечислите хотя бы вы десяток «чистых» функций


Вот вам одна:
int CalcSomething(int a, int b)
{
return (a - b)/b;
}


«Чистая» она в том смысле, что не имеет защитных проверок, например самой банальной — на равенство b нулю.

Вообще тестирование такая важная вещь что лучше его встраивать в релизный код как это и делается в отвественных системах


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

не понял что конкретно тестировалось

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

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

Хорошо, вот из моего текущего домашнего проекта:
  • bool ButtonClick_IsDetected() — проверяет произошло-ли нажатие кнопки
  • int32_t EncoderOffset_Get() — возвращает смещение энкодера
  • ClockDisplay_SetTime(time) — устанавливает время на дисплее часов
  • ClockDisplay_SetMode(mode) — устанавливает режим отображения для дисплея часов
  • ClockDisplay_Periodic() — периодически вызываемая функция, вызывает смену кадра анимации
  • Animation_ShowTime_Enter(animationParameters) — активирует анимацию отображения времени
  • uint32_t Animation_AntiPoisoning_GetMinimalDuration() — возвращает минимальную допустимую длительность анимации перебора разрядов
  • Animation_AntiPoisoning_Enter(animationParameters) — активирует анимацию перебора разрядов для предотвращения отравления катодов
  • Animation_AntiPoisoning_Periodic(time) — выводит следующий кадр анимации перебора разрядов
  • Animation_EditHours_Enter(animationParameters) — активирует анимацию редактирования часов

Помогло?

Не ясна совокупная выгода такого подхода и контекст.

Выгода заключается по меньшей мере в уменьшении количества неотловленных ошибок, облегчении редактирования кода (тесты покажут что после изменений не сломалось по крайней мере то что они тестируют), улучшении качества кода (более мелкие модули с меньшей связанностью, большее соответствие принципам SOLID). В численном виде выразить сложно, но попытки были — если есть много свободного времени то можно поискать и поизучать research papers по этой теме в интернете. Контекст — написание программ.

это же не тестирование, а моделирование

Нет, это не моделирование. Моделирование подразумевает описание реакции модели на все возможные ситуации в которых она может оказаться. При модульном тестировании в пределах каждого теста описывается один-единственный сценарий взаимодействия. «Если светофор переключился на красный свет, то автопилот должен затормозить»; «если светофор переключился на зелёный свет и дорога свободна, то автопилот должен начать движение» — для проверки этих утверждений вам не нужно моделировать весь светофор и окружающую его улицу.

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

Не моделирование датчиков, а тестирование кода который будет с ними работать. Идея в том что значительная часть информации доступна заранее, а расхождения можно будет скорректировать когда о них станет известно. Как говорят Томас и Хант в «Прагматичном рпограммисте» — качественный код это такой код, который легко поддаётся изменению.
Моделирование подразумевает описание реакции модели на все возможные ситуации в которых она может оказаться.

Я с этим не согласен.
Моделирование — это реализация некоторых известных вам аспектов поведения с возможностью коррекции, ради чего моделирование и устраивается.
Если вы «тестируете» датчик которого не держали в руках, то это моделирование датчика, а не тестирование.
Все возможные ситуации для реальных моделей описать нереалистично.

Как говорят Томас и Хант в «Прагматичном рпограммисте» — качественный код это такой код, который легко поддаётся изменению.

Здесь я с Томасом и Хантом полность согласен.
И устроенный автором процесс минимум в два раза усложняет изменения, в чем он и признался.

Приведенный вами список функций интересен.
Я тоже широко использую GUI, работаю с энкодерами и часами и много с чем.
Но считаю что юнит-тестировать такие функции GUI не имеет особого смысла.
Они тестируется в режиме Test-driven development. И оставлять рудименты в виде юнит-тестов после этого не нужно.
И некоторые ваши функции без аргументов.
Т.е. к ним неприменимо юнит-тестирование, как тут его описывают.
Что же за тестирование у вас в таком случае?
Они тестируется в режиме Test-driven development. И оставлять рудименты в виде юнит-тестов после этого не нужно.

Ээээ, то есть вы пишете в стиле TDD — а потом тесты удаляете? Но ведь тесты — это гарантия того, что новые изменения не сломают старый функционал.


Или по-вашему TDD — это когда вы что-то написали, вручную проверили — работает, все?


И некоторые ваши функции без аргументов.
Т.е. к ним неприменимо юнит-тестирование, как тут его описывают.
Что же за тестирование у вас в таком случае?

Эти функции могут опираться на какое-то глобальное состояние; не только чистые (в всмысле ФП) функции можно тестировать — хотя, конечно, проще.


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


Моделирование — это реализация некоторых известных вам аспектов поведения с возможностью коррекции, ради чего моделирование и устраивается.
Если вы «тестируете» датчик которого не держали в руках, то это моделирование датчика, а не тестирование.

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

Я с этим не согласен.

Ох как неловко вышло… Надо пойти всем рассказать, а то тысячи и миллионы глупцов называют юнит-моделирование юнит-тестированием и даже не догадываются! Спасибо за вашу мудрость.

устроенный автором процесс минимум в два раза усложняет изменения

Вы этот вывод сделали из того что кода больше писать? Ну да, действительно. Вот бы у меня тоже сложность программирования зависела только от скорости печати. Восхищён вами.

считаю что юнит-тестировать такие функции GUI не имеет особого смысла

Извините, немедленно удалю все тесты.

Они тестируется в режиме Test-driven development. И оставлять рудименты в виде юнит-тестов после этого не нужно. И некоторые ваши функции без аргументов. Т.е. к ним неприменимо юнит-тестирование, как тут его описывают. Что же за тестирование у вас в таком случае?

Так у вас какой-то свой, новаторский Test Driven Development, с удалением тестов после того как они становятся не нужны? И с обязательным наличием аргументов у всех функций тестируемого кода? Гениально! Нужно немедленно связаться с Кентом Беком и Джеймсом Греннингом, они оказывается все эти годы делали какую-то фигню. Невероятно!

А если серьёзно — вы, пожалуйста, почитайте книжек умных прежде чем утверждениями бросаться. Я понимаю что ваши вопросы появились из-за того что статью вы не поняли, но обычно тон комментариев в таких случаях вопросительный, а не поучающий всех подряд что и как правильно.
Я понимаю что ваши вопросы появились из-за того что статью вы не поняли, но обычно тон комментариев в таких случаях вопросительный, а не поучающий всех подряд что и как правильно.

Понять это видимо в вашем понимании — принять.
Я собственно в вопросительном тоне и пишу. Автор отвечает что я неправильно спрашиваю. Как вам это?

Да, мелкие тесты удаляются беспощадно.
Вы привели пример удивительно мелких тестов.
Это перерасход рабочего времени на поддержку и на рефакторинг.
Какие есть основания так мелко гранулировать тестирование?

И как у автора везде сквозит — это всего лишь административные меры для навязывания стиля остальным программистам.

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

Как могут рухнуть такие мелкие функции если вы их сами написали, сами поддерживаете и сами рефакторите? Это что не то уже с памятью. Так тут не помогут никакие тесты.
Но если у вас реально сложные функции с большим количеством состояний, то юнит-тестирование предложенное здесь — детский лепет.

А упомянутые вами авторы занимаются проблемами командного программирования. Но есть просто огромная разница между методами командного программирования и индивидуального.
А упомянутые вами авторы занимаются проблемами командного программирования

Ага, особенно Греннинг.

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

Искренне надеюсь что нам никогда не придётся работать вместе. Всего доброго.
Я собственно в вопросительном тоне и пишу. Автор отвечает что я неправильно спрашиваю. Как вам это?

Я не знаю, какое мое сообщение вы умудрились так прочесть; я пытаюсь уточнить, что же вы хотите увидеть — но на мои комментарии вы отвечать перестали… ну ладно, как вам будет угодно.


Я все-таки продолжу комментировать, пусть не для вас, но для других читателей :)


И как у автора везде сквозит — это всего лишь административные меры для навязывания стиля остальным программистам.

Да, отчасти это так. И в командной разработке единство стиля — это очень важно; члены команды должны иметь возможность понимать код друг друга.


Как могут рухнуть такие мелкие функции если вы их сами написали, сами поддерживаете и сами рефакторите? Это что не то уже с памятью. Так тут не помогут никакие тесты.
Но если у вас реально сложные функции с большим количеством состояний, то юнит-тестирование предложенное здесь — детский лепет.

Нуэмм… как бы вам объяснить?
Очень нежелательно писать огромные сложные функции со множеством состояний — их трудно читать, их трудно тестировать.
Поэтому такие функции разбиваются на отдельные более простые части, которые тестируются по отдельности.


А затем тестируются все целиком.


Если пользоваться методикой "протестил — удалил тест" или "протестил компонент вручную", то вы либо доверяете своей памяти, либо ведете какой-то журнал протестированного… видимо.


Я своей памяти не настолько доверяю, а журнал вести лень — зачем, вот же тесты есть. Зачем их удалять-то?


Как могут рухнуть такие мелкие функции если вы их сами написали, сами поддерживаете и сами рефакторите

Как раз-таки не факт, что их я поддерживать буду сам! Я же не один работаю.


А упомянутые вами авторы занимаются проблемами командного программирования. Но есть просто огромная разница между методами командного программирования и индивидуального.

Допустим. Но вы же не считаете, что в embedded не существует командной разработки?


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


А тесты — это как еще один слой документации, как небольшие примеры использования кода и демонстрация его поведения.

Не то что бы я специально не отвечал на ваши комментарии, но просто не так много времени имею.

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

Я вообще не спец в организации коллективного программирования.
Поэтому и очертил свою организацию работы чтобы не спорить о несоотносимых вещах.

Но память — хитрый механизм. И она затачивается.
Какой бы способ не применили память заточится под него.
Поэтому да, история ошибок важна и я ее храню в архиве версий.
На самые распространенные типа утечек памяти или пустых указателей у меня выработан рефлекс автоматической 10-и кратной самопроверки и аскетизм синтаксиса. С++ ни в коем разе — это мультипликатор забивающих память сущностей. (но в коллективном программировании — ничего против)
На сложные автоматы состояний, я вообще не пишу код, а генерирую его из моделей в MATLAB-е. Тут, кстати, не поуправляешь простой функций. MATLAB запросто выдаст портянку на 100 кБ содержащую только одну функцию!
И наконец для кусков коммуникационных стеков, файловых систем и прочих крупных модулей у меня всегда в релизном приложении храняться интеграционные тесты, которые запускаются из закрытого для юзеров меню.
И все, места юнит-тестам нет. Есть только короткие исследовательские тесты.
Если нужно они остаются в ветках хранилища версий.



Штош. У вас процесс разработки существенно отличается от нашего, поэтому вам я ничего возразить по сути не могу.
Единственное, что если бы вы это описали сразу, то ваши, скорее всего, замечания не воспринимались бы так резко :)


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


Генерированный код тестить, конечно, дело неблагодарное; наверное, логичнее было бы тестить собственно модели в матлабе? Но как это делать (и нужно ли) — не знаю; матлабом не пользуюсь. Так что тут вам видней.

Бегом пробежался пока, с первого взгляда, хорошая статья получилась. Есть вопросы.


  1. Чем моки вы создаёте?
  2. Поддерживает ли последний рассмотренный фреймворк с++17 и шаблоны? Ну типа, variadic templates?

Спасибо :)


Моки — просто руками -_- Не дорос я до генераторов.
Для часто используемых вещей моки просто уже написаны.


Поддерживает ли последний рассмотренный фреймворк с++17 и шаблоны? Ну типа, variadic templates?

Последний фреймворк — всмысле мой велосипед? Ну, сам он под с++17 должен собраться (хотя я не проверял, но там зависимостей даже от С++11 нет жестких).


А что вы имеете в виду под поддержкой?

Для часто используемых вещей моки просто уже написаны.

Я имею ввиду, что моки все равно нужно делать практически для каждого теста свои, даже если один и тот же модуль и вроде как мок один тоже должен быть, но разные методы одного класса и тесты к ним пишут разные программисты и каждый под свой метод делает отдельный мок.
Есть всякие фреймворк для моков, типа CppUMock, которые позволяют часть работы упростить. Есть вообще полностью автоматизированные юнит тест фреймворки типа VectorCASTа, там про моки даже не вспоминаешь, они создаются автоматом под твой тест — но они дорогие.


Вообще небольшой обзор фич фреймворков есть тут:
https://en.m.wikipedia.org/wiki/List_of_unit_testing_frameworks


Последний фреймворк — всмысле мой велосипед? Ну, сам он под с++17 должен собраться (хотя я не проверял, но там зависимостей даже от С++11 нет жестких).

Да. :)


А что вы имеете в виду под поддержкой?

Ну не все фреймворки умеют тестировать такое. Колонка templates в ссылке, что я дал.

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

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


Иначе говоря, я пока не испытываю острой потребности в генерации моков (а может быть просто не осознаю ее), поэтому в эту сторону копать не стал :)


Ну не все фреймворки умеют тестировать такое. Колонка templates в ссылке, что я дал.

Боюсь, по-прежнему не понимаю, что вы имеете в виду. По ссылке буквально просто "колонка templates", без пояснений :D


Типа, тестить допустимые параметры у метафункций? Такое — нет; насколько я понимаю, для этого нужны или тесты на уровне системы сборки или какие-то извращения с unevaluated context или SFINAE, честно говоря особо не задумывался.

Уже не занимаюсь разработкой на МК, но я бы разделил код работы с железом и основную логику
далее основную логику юнит тестами на хосте, железо на тестовом стенде/симуляторе
к тому же обычно у меня работа с железом пишется один раз и переходит из проекта в проект

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

Отличная статья, благодарю. Я правильно понимаю что Вы были первым на своём месте работы, кто начал применять юнит-тесты и убедил в их пользе коллег? Расскажите, пожалуйста, как Вам удалось последнее.
Я правильно понимаю что Вы были первым на своём месте работы, кто начал применять юнит-тесты и убедил в их пользе коллег? Расскажите, пожалуйста, как Вам удалось последнее.

Не совсем так. Начался вот тот самый проект для военных, с полугодовыми сроками поставок, и мысль о необходимости тестов как-то одновременно забрела нескольким людям в головы, по совершенно рациональным соображениям. Как-то так вышло, что за практическое велосипедостроение сел я, ну и завертелось.
А с годами "противники" тестов потихоньку от нас уволились :)


Но вообще — я не могу сказать (и в посте вроде бы тоже не утверждал такого), что у нас прям все радужно, покрытие 100% и бегают TDD-шные единороги. Сейчас более-менее покрыты только наши самодельные библиотеки и отдельные куски в проектах (опять же, те, которые одновременно легко тестить и очень нужно протестить).


Так что увы, никакого управленческого чуда.

Отличная статья! Правда огромная, и с первого раза ее осилить невозможно. Впрочем все ваши предыдущие статьи и комменты по теме юнит-тестирования в МК я читал уже, так что как-нибудь на свежую голову и эту статью осилю. :)

Холиварить насчет необходимости юнит-тестов бесполезно, поскольку противники либо просто не в теме (и это в коллективах обычно становится проблемой амбассадора, а не противников), либо просто искренне не имеют тех проблем, о которых все пишут (причем, serious, они могут просто не допускать тех ошибок, ради которых все это нужно, либо умеют быстро их находить, а реально сложные ошибки все равно лежат в сфере интеграционного тестирования). А вот найти «серебряную пулю» и всех заставить ее использовать без оговорок было бы интересно. Кажется на эту роль только googletest претендует, но это только для плюсов, а для Си особо ничего и нет (MinUnit конечно не тестовый фреймворк, а фигня).
Отличная статья! Правда огромная, и с первого раза ее осилить невозможно. Впрочем все ваши предыдущие статьи и комменты по теме юнит-тестирования в МК я читал уже, так что как-нибудь на свежую голову и эту статью осилю. :)

Я польщен :) Статью, наверное, можно рассматривать или как тутор или как какой-нибудь справочник и не читать целиком — я просто постарался зафиксировать как можно больше "набитых шишек".


они могут просто не допускать тех ошибок, ради которых все это нужно, либо умеют быстро их находить, а реально сложные ошибки все равно лежат в сфере интеграционного тестирования).

Согласен, неоднократно наблюдал таких людей и прям не понимаю, как они это делают. Я постоянно косячу без тестов ._. Причем с каждым годом косяки по сути те же, но находить их становится все сложнее и сложнее… Очень странный эффект.


А вот найти «серебряную пулю» и всех заставить ее использовать без оговорок было бы интересно. Кажется на эту роль только googletest претендует, но это только для плюсов, а для Си особо ничего и нет (MinUnit конечно не тестовый фреймворк, а фигня).

Если бы я сейчас выбирал фреймворк и не был ограничен упоротыми компиляторами для МК, то наверное взял бы Catch2; но эт дело вкуса.


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

На мой взгляд любое автоматизированное тестирование лучше, чем никакое. А в embedded, по моим наблюдениям, оно в основном никакое.


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

Пожалуй, я могу только позавидовать вашему опыту.
Я в основном вижу совсем другое ._.

Тут завидовать нечему. Если вы внимательно читали (и если я верно передал мысль), то дело не в том, что все кругом покрыто рантаймовыми проверками и ни один баг не прокрадется, а в том, что оно покрывается в какой-то мере, и из этого авторами делаются далекоидущие выводы и обещания. При том что, повторюсь, наличие рантаймовых проверок — как раз самый яркий повод вставить тесты этих самых проверок.

Как вам сказать… я очень часто вижу людей, которые настолько плохо понимают, что такое разработка, что даже не понимают, что не так. Они не слышали ни про контроль версий, ни про комментарии, ни про что вообще. И им нормально, они не видят проблемы. Ну типа работает же.


Им пофиг, что функции на 3000 строк невозможно читать — их код просто никто никогда не читает, кроме них самих.


Какое уж там защитное программирование -_-'

Да, ассерты в SPL и HAL — достаточно полезная штука; хотя примерно половину можно было бы убрать, если вместо uint16_t параметры у функций были бы enum class (я понимаю, что они не могут, но помечтать-то можно).


А вот у LL ассертов на порядок меньше, это немного напрягает.

Спасибо. Разжевано, что называется, для особо тупых.

Sign up to leave a comment.

Articles