Краткое введение в этот вопрос. Я использовал сейчас TDD и в последнее время BDD уже более года. Я использую такие приемы, как издевательство, чтобы писать свои тесты более эффективно. В последнее время я начал личный проект, чтобы написать небольшую программу управления капиталом для себя. Поскольку у меня не было устаревшего кода, это был идеальный проект, чтобы начать с TDD. К сожалению, я не испытал столько радости от TDD. Это даже настолько испортило мое веселье, что я разочаровался в проекте.
В чем была проблема? Ну, я использовал подход, подобный TDD, чтобы тесты / требования развивали дизайн программы. Проблема заключалась в том, что более половины времени разработки приходилось на написание / рефакторинг тестов. В итоге я не хотел реализовывать больше функций, потому что мне нужно было бы провести рефакторинг и написать множество тестов.
На работе у меня много устаревшего кода. Здесь я пишу все больше интеграционных и приемочных тестов и меньше юнит-тестов. Это не кажется плохим подходом, поскольку ошибки в основном выявляются при приемочных и интеграционных тестах.
Моя идея состояла в том, чтобы я мог в итоге написать больше интеграционных и приемочных тестов, чем модульных. Как я уже говорил, для выявления ошибок юнит-тесты не лучше, чем интеграционные / приемочные тесты. Модульные испытания также хороши для дизайна. Так как я писал много из них, мои занятия всегда были хорошими для тестирования. Кроме того, подход к тестированию / требованиям, которым следует руководствоваться при проектировании, в большинстве случаев приводит к улучшению дизайна. Последнее преимущество юнит-тестов в том, что они быстрее. Я написал достаточно интеграционных тестов, чтобы знать, что они могут быть почти такими же быстрыми, как и модульные тесты.
После того, как я искал через Интернет , я обнаружил, что есть очень похожие идеи , помоему , упомянутые здесь , и там . Что вы думаете об этой идее?
редактировать
Отвечая на вопросы, один пример, где дизайн был хорош, но мне потребовался огромный рефакторинг для следующего требования:
Сначала были некоторые требования для выполнения определенных команд. Я написал расширяемый анализатор команд, который анализировал команды из какой-либо командной строки и вызывал правильную в модели. Результат был представлен в классе модели представления:
Здесь не было ничего плохого. Все классы были независимы друг от друга, и я мог легко добавлять новые команды, показывать новые данные.
Следующим требованием было, чтобы у каждой команды было собственное представление представления - своего рода предварительный просмотр результата команды. Я переработал программу, чтобы добиться лучшего дизайна для нового требования:
Это было также хорошо, потому что теперь у каждой команды есть своя собственная модель представления и, следовательно, собственный предварительный просмотр.
Дело в том, что синтаксический анализатор команд был изменен на использование анализа команд на основе токенов и лишен возможности выполнять команды. Каждая команда получила свою собственную модель представления, и модель представления данных знает только текущую модель представления команды, которая знает данные, которые должны быть показаны.
Все, что я хотел бы знать на данный момент, - если новый дизайн не нарушает каких-либо существующих требований. Мне не нужно было менять ЛЮБОЙ мой приемочный тест. Мне пришлось провести рефакторинг или удалить почти КАЖДЫЕ юнит-тесты, что было огромной кучей работы.
Здесь я хотел показать общую ситуацию, которая часто случалась во время разработки. Не было никаких проблем со старым или новым дизайном, они просто менялись естественным образом в соответствии с требованиями - насколько я понял, это одно из преимуществ TDD в том, что дизайн развивается.
Заключение
Спасибо за все ответы и обсуждения. Подводя итог этой дискуссии, я подумал о подходе, который я опробую в своем следующем проекте.
- Прежде всего, я пишу все тесты, прежде чем реализовать что-либо, как всегда делал.
- Для требований я пишу сначала несколько приемочных тестов, которые тестируют всю программу. Затем я пишу несколько интеграционных тестов для компонентов, где мне нужно реализовать требование. Если есть компонент, который тесно взаимодействует с другим компонентом для реализации этого требования, я бы также написал несколько интеграционных тестов, в которых оба компонента тестируются вместе. И последнее, но не менее важное, если мне нужно написать алгоритм или любой другой класс с высокой перестановкой - например, сериализатор - я бы написал модульные тесты для этих конкретных классов. Все остальные классы не тестируются, а проходят какие-либо юнит-тесты.
- Для ошибок этот процесс может быть упрощен. Обычно ошибка вызвана одним или двумя компонентами. В этом случае я бы написал один интеграционный тест для компонентов, который тестирует ошибку. Если бы это касалось алгоритма, я бы написал только тестовый модуль. Если не легко обнаружить компонент, где возникает ошибка, я бы написал приемочный тест, чтобы найти ошибку - это должно быть исключением.