Очень часто стоит только сказать коллеге: «Там упало пару тестов и надо...» он даже договорить не даст
У нас в команде всеми принято правило — мы не коммитим код, если не проходят модульные тесты. То есть, стараемся исключить ситуацию нестабильной ветки разработки. Поэтому таких проблем пока еще не возникало.
Вот когда будет, тогда и надо задуматься о том что пора писать тест.
Может получиться ситуация, когда тест будет написать очень сложно. Потому что уже принято какое-то архитектурное решение и это решение не позволяет легко написать модульный тест.
Вполне возможно, что такой подход — специфика вашей работы.
И как называются такие тесты? Которые запускаются с юнит-тестами, на них похожи, полностью автономны от внешних зависимостей и т.п.
Терминология и определения это вообще очень скользкая тема. Если жестко следовать всем определениям, то часть кода тестируется (как правило, не самая важная), а часть нет. В итоге, если сказать, что мы вот это и вот это не тестируем, то количество кода в нетестируемых местах начинает планомерно увеличиваться.
В общем, мы решили использовать другую классификацию тестов.
Функциональные тесты — это тесты, предназначенные для проверки функционирования какого-либо компонента программной системы. Грубо говоря, если наша система состоит из набора исполняемых модулей, то тестирование одного такого модуля будет являться функциональным. То есть, компонент системы является «чёрным ящиком» для которого описывается, что при входном значении X на выходе будет значение Y или, если рассматривать приложение типа WinForms, описание может выглядеть так: «Если нажать на эту кнопочку, то в этом поле появится такое-то значение». Проверка подобных условий и будет являться функциональным тестированием.
Интеграционные тесты — это тесты, предназначенные для тестирования системы в целом. Не отдельных компонентов, как в случае с функциональными тестами, а всей системы. Тесты этой группы самые «дорогие». Ведь зачастую, чтобы развернуть систему, требуется достаточно много времени и ресурсов. Иногда даже приходится дёргать системных администраторов, которые не всегда горят желанием заниматься проблемами разработчиков. В общем, интеграционное тестирование я отношу к разряду «экстремальных».
Ну и наконец, модульные или unit тесты — это тесты, предназначенные для проверки логики работы программных компонентов. Таких как классы, методы, процедуры или функции. Эти тесты самые «дешёвые» среди трёх. Для того, чтобы протестировать логику работы метода или функции не требуется прилагать какие-то значительные усилия. Всё, что нужно уже есть или доступно в рабочем окружении программиста. Ну, а раз модульные тесты наиболее доступны по сравнению с функциональными и интеграционными, то имеет смысл сосредоточиться именно на них и постараться получить от их использования максимум выгоды, что, собственно, и предполагает TDD.
bool ElfParser::isCorrected( const char * data, int data_len );
Извините, но не могу понять для чего нужна функция. Возможно, что при наличии теста мне было бы немного проще. Это я о том, нужно ли писать тест на очевидные вещи. Проблема в том, что они могут быть неочевидны кому-то ещё.
лучше применять вопросы: «Насколько сложна функция? Код функции уже устоялся?». Если оба вопроса «да», значит пишем тест, иначе мы просто задолбаемся актуализировать тесты.
Гм… верно ли я понял, что вы пишете тест после реализации и определения сложности функции?
Закономерный комментарий. Потребность тестировать взаимодействие с базой данных появилась из желания максимально использовать возможности модульного тестирования на проекте. То есть тестировать всё, что получится протестировать. Ну, а желание это продиктовано стоимостью ошибки. Чем раньше и полнее протестирована система, тем «дешевле», в конечном итоге, будут обнаруженные ошибки. Ведь даже если ошибки обнаружены отделом тестирования, их исправление является достаточно затратным занятием, не говоря уже об исправлении ошибок, обнаруженных в системе, отданной в эксплуатацию. Поэтому приходится искать компромисс между скоростью выполнения тестов и затратами на использование внешних ресурсов.
В общем, здесь скорее не противоречие, а некая «золотая середина».
То, о чём вы говорите верно в том случае, если используется одна база данных на весь набор тестов. В этом случае тесты становятся связанными между собой через базу данных и приходится чистить базу после выполнения каждого теста. И вполне возможна ситуация, при которой изменения в одном тесте влекут за собой падение всего набора. Тогда да, приходится отлаживать тесты. Не самая приятная ситуация. У нас был такой опыт. После которого мы пришли к тому решению, которое и описано в статье. База данных всегда новая. Создается перед выполнением теста. Полностью чистая. И каждый тест наполняет базу именно теми данными, которые ему нужны для работы. То есть выполняются предусловия, действие и постусловия.
У нас в команде всеми принято правило — мы не коммитим код, если не проходят модульные тесты. То есть, стараемся исключить ситуацию нестабильной ветки разработки. Поэтому таких проблем пока еще не возникало.
Может получиться ситуация, когда тест будет написать очень сложно. Потому что уже принято какое-то архитектурное решение и это решение не позволяет легко написать модульный тест.
Вполне возможно, что такой подход — специфика вашей работы.
Терминология и определения это вообще очень скользкая тема. Если жестко следовать всем определениям, то часть кода тестируется (как правило, не самая важная), а часть нет. В итоге, если сказать, что мы вот это и вот это не тестируем, то количество кода в нетестируемых местах начинает планомерно увеличиваться.
В общем, мы решили использовать другую классификацию тестов.
Функциональные тесты — это тесты, предназначенные для проверки функционирования какого-либо компонента программной системы. Грубо говоря, если наша система состоит из набора исполняемых модулей, то тестирование одного такого модуля будет являться функциональным. То есть, компонент системы является «чёрным ящиком» для которого описывается, что при входном значении X на выходе будет значение Y или, если рассматривать приложение типа WinForms, описание может выглядеть так: «Если нажать на эту кнопочку, то в этом поле появится такое-то значение». Проверка подобных условий и будет являться функциональным тестированием.
Интеграционные тесты — это тесты, предназначенные для тестирования системы в целом. Не отдельных компонентов, как в случае с функциональными тестами, а всей системы. Тесты этой группы самые «дорогие». Ведь зачастую, чтобы развернуть систему, требуется достаточно много времени и ресурсов. Иногда даже приходится дёргать системных администраторов, которые не всегда горят желанием заниматься проблемами разработчиков. В общем, интеграционное тестирование я отношу к разряду «экстремальных».
Ну и наконец, модульные или unit тесты — это тесты, предназначенные для проверки логики работы программных компонентов. Таких как классы, методы, процедуры или функции. Эти тесты самые «дешёвые» среди трёх. Для того, чтобы протестировать логику работы метода или функции не требуется прилагать какие-то значительные усилия. Всё, что нужно уже есть или доступно в рабочем окружении программиста. Ну, а раз модульные тесты наиболее доступны по сравнению с функциональными и интеграционными, то имеет смысл сосредоточиться именно на них и постараться получить от их использования максимум выгоды, что, собственно, и предполагает TDD.
Извините, но не могу понять для чего нужна функция. Возможно, что при наличии теста мне было бы немного проще. Это я о том, нужно ли писать тест на очевидные вещи. Проблема в том, что они могут быть неочевидны кому-то ещё.
Гм… верно ли я понял, что вы пишете тест после реализации и определения сложности функции?
В общем, здесь скорее не противоречие, а некая «золотая середина».
Про экзамен на дизайн — спасибо!