TL; DR
Написание хороших, полезных тестов сложно и дорого обходится в C ++. Можете ли вы опытные разработчики поделиться своим обоснованием того, что и когда тестировать?
Длинная история
Раньше я занимался разработкой на основе тестов, фактически, всей моей командой, но у нас это не получалось. У нас есть много тестов, но они, кажется, никогда не охватывают случаи, когда у нас есть реальные ошибки и регрессии - которые обычно происходят, когда юниты взаимодействуют, а не из-за их изолированного поведения.
Это часто настолько сложно протестировать на уровне модулей, что мы перестали использовать TDD (за исключением компонентов, где это действительно ускоряет разработку), и вместо этого потратили больше времени на расширение охвата интеграционных тестов. Несмотря на то, что небольшие модульные тесты никогда не выявляли реальных ошибок и были в основном просто накладными расходами на обслуживание, интеграционные тесты действительно стоили усилий.
Теперь я унаследовал новый проект, и мне интересно, как его протестировать. Это родное приложение C ++ / OpenGL, поэтому интеграционные тесты на самом деле не подходят. Но модульное тестирование в C ++ немного сложнее, чем в Java (вы должны явно делать вещи virtual
), и программа не сильно объектно-ориентирована, поэтому я не могу издеваться над некоторыми вещами.
Я не хочу разрывать и разбирать все это, просто чтобы написать несколько тестов ради написания тестов. Поэтому я спрашиваю вас: для чего мне писать тесты? например:
- Функции / Классы, которые я ожидаю часто менять?
- Функции / классы, которые сложнее проверить вручную?
- Функции / классы, которые уже легко проверить?
Я начал исследовать некоторые уважительные базы кода C ++, чтобы увидеть, как они идут на тестирование. Прямо сейчас я изучаю исходный код Chromium, но мне трудно извлечь обоснование их тестирования из кода. Если у кого-нибудь есть хороший пример или пост о том, как к этому подходят популярные пользователи C ++ (ребята из комитета, авторы книг, Google, Facebook, Microsoft, ...), это было бы очень полезно.
Обновить
Я искал свой путь вокруг этого сайта и в Интернете с момента написания этого. Найдены хорошие вещи:
- Когда уместно не проводить модульное тестирование?
- /programming/109432/what-not-to-test-when-it-comes-to-unit-testing
- http://junit.sourceforge.net/doc/faq/faq.htm#best
К сожалению, все они скорее ориентированы на Java / C #. Написание большого количества тестов на Java / C # не является большой проблемой, поэтому выгода обычно перевешивает затраты.
Но, как я уже писал выше, в C ++ это сложнее. Особенно, если ваша кодовая база не так уж и хороша, вам придется серьезно испортить ситуацию, чтобы получить хороший охват модульных тестов. Например: у приложения, которое я унаследовал, есть Graphics
пространство имен, которое является тонким слоем над OpenGL. Чтобы протестировать любую из сущностей - которые все используют ее функции напрямую - мне нужно было бы превратить это в интерфейс и класс и внедрить его во все сущности. Это только один пример.
Поэтому, отвечая на этот вопрос, имейте в виду, что я должен сделать довольно большие инвестиции для написания тестов.
источник
Ответы:
Ну, юнит тестирование это только одна часть. Интеграционные тесты помогут вам решить проблему вашей команды. Интеграционные тесты могут быть написаны для всех видов приложений, а также для нативных приложений и приложений OpenGL. Вы должны проверить «Растущее объектно-ориентированное программное обеспечение под руководством тестов» Стива Фриманна и Ната Прайса (например, http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627 ). Он шаг за шагом ведет вас к разработке приложения с графическим интерфейсом и сетевым взаимодействием.
Тестирование программного обеспечения, которое не было протестировано, - другая история. Проверьте Майкла Фезерса «Эффективная работа с устаревшим кодом» (http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052).
источник
Обидно, что TDD "не сработал для вас". Я думаю, что это ключ к пониманию, куда обратиться. Пересмотрите и поймите, как TDD не работает, что вы могли бы сделать лучше, почему возникли трудности.
Поэтому, конечно, ваши юнит-тесты не уловили найденных вами ошибок. Это своего рода точка. :-) Вы не нашли этих ошибок, потому что в первую очередь предотвратили их возникновение, подумав, как должны работать интерфейсы и как убедиться, что они были протестированы должным образом.
Чтобы ответить, вы задаете вопрос, как вы пришли к выводу, что код модульного тестирования, который не предназначен для тестирования, является трудным. Для существующего кода может быть более эффективно использовать функциональную среду или среду тестирования интеграции, а не среду модульного тестирования. Протестируйте систему в целом, ориентируясь на конкретные области.
Конечно, новые разработки выиграют от TDD. По мере добавления новых функций рефакторинг для TDD может помочь протестировать новую разработку, а также позволит разработать новый модульный тест для унаследованных функций.
источник
Я не делал TDD в C ++, поэтому я не могу это комментировать, но вы должны проверить ожидаемое поведение вашего кода. Хотя реализация может измениться, поведение должно (обычно?) Оставаться прежним. В мире, ориентированном на Java \ C #, это будет означать, что вы будете тестировать только общедоступные методы, писать тесты на ожидаемое поведение и делать это до реализации (что обычно лучше сказать, чем сделать :)).
источник