Наш коллега продвигает написание модульных тестов, поскольку на самом деле помогает нам дорабатывать дизайн и реорганизовывать вещи, но я не понимаю, как это сделать. Если я загружаю файл CSV и анализирую его, как модульный тест (проверка значений в полях) поможет мне проверить мой дизайн? Он упомянул связность и модульность и т. Д., Но для меня это не имеет особого смысла - хотя у меня нет большого теоретического фона.
Это не то же самое, что вопрос, который вы отметили как дубликат, меня интересуют реальные примеры того, как это помогает, а не просто теория, говорящая «это помогает». Мне нравится ответ ниже и комментарий, но я хотел бы узнать больше.
design
unit-testing
object-oriented-design
User039402
источник
источник
Ответы:
Модульные тесты не только облегчают разработку, но и являются одним из их ключевых преимуществ.
Написание test-first устраняет модульность и чистую структуру кода.
Когда вы пишете свой код сначала в тестовом режиме, вы обнаружите, что любые «условия» данного блока кода естественным образом вытесняются в зависимости (обычно через макеты или заглушки), когда вы принимаете их в своем коде.
«При заданном условии x ожидаемое поведение y» часто становится заглушкой для поставки
x
(что является сценарием, в котором тест должен проверять поведение текущего компонента) иy
становится имитацией, вызов которой будет проверен в конец теста (если это не «должен возвращатьсяy
», в этом случае тест просто будет явно проверять возвращаемое значение).Затем, когда этот модуль ведет себя так, как указано, вы переходите к записи зависимостей (для
x
иy
), которые вы обнаружили.Это делает написание чистого, модульного кода очень простым и естественным процессом, в противном случае зачастую легко распутать обязанности и объединить поведение, не осознавая этого.
Написание тестов позже скажет вам, когда ваш код плохо структурирован.
Когда написание тестов для части кода становится трудным, потому что слишком много вещей, которые нужно заглушить или смоделировать, или потому что вещи слишком тесно связаны друг с другом, вы знаете, что нужно внести улучшения в свой код.
Когда «смена тестов» становится обузой, потому что в одном модуле так много поведений, вы знаете, что вам нужно внести улучшения в свой код (или просто в свой подход к написанию тестов - но в моем опыте это обычно не так) ,
Когда ваши сценарии становятся слишком сложными ( «если
x
иy
иz
затем ...») , потому что вам нужно абстрагировать больше, вы знаете , у вас есть улучшения , чтобы сделать в вашем коде.Когда вы получаете одинаковые тесты в двух разных приборах из-за дублирования и избыточности, вы знаете, что в вашем коде необходимо внести улучшения.
Вот отличный доклад Майкла Фезерса, демонстрирующий очень тесную связь между тестируемостью и дизайном в коде (первоначально опубликованный displayName в комментариях). В докладе также рассматриваются некоторые распространенные жалобы и неправильные представления о хорошем дизайне и тестируемости в целом.
источник
Самое замечательное в модульных тестах - они позволяют вам использовать ваш код так же, как другие программисты будут использовать ваш код.
Если ваш код неудобен для модульного тестирования, то, вероятно, его будет неудобно использовать. Если вы не можете внедрить зависимости без скачков, то ваш код, вероятно, будет негибким в использовании. И если вам нужно потратить много времени на настройку данных или выяснить, в каком порядке действовать, ваш тестируемый код, вероятно, слишком сильно связан, и с ним будет трудно работать.
источник
Мне потребовалось много времени, чтобы осознать, но реальная выгода (отредактируйте: для меня ваш возраст может отличаться) от разработки, основанной на тестировании ( с использованием модульных тестов), заключается в том, что вы должны разрабатывать API заранее !
Типичный подход к разработке состоит в том, чтобы сначала выяснить, как решить данную проблему, и с этими знаниями и первоначальной реализацией разработать способ вызова вашего решения. Это может дать довольно интересные результаты.
При выполнении TDD вы должны в первую очередь написать код, который будет использовать ваше решение. Входные параметры и ожидаемый результат, чтобы вы могли убедиться, что это правильно. Это, в свою очередь, требует, чтобы вы выяснили, что вам на самом деле нужно, чтобы он делал, чтобы вы могли создавать содержательные тесты. Тогда и только тогда вы реализуете решение. По моему опыту, когда вы точно знаете, чего должен достичь ваш код, это становится понятнее.
Затем, после реализации модульные тесты помогут вам убедиться, что рефакторинг не нарушает функциональность, и предоставят документацию о том, как использовать ваш код (что, как вы знаете, верно при прохождении теста!). Но они вторичны - самое большое преимущество - это мышление при создании кода.
источник
Я бы согласился на 100%, что модульные тесты помогают «помочь нам усовершенствовать дизайн и рефакторинг».
У меня два мнения о том, помогут ли они вам сделать первоначальный дизайн . Да, они обнаруживают очевидные недостатки и заставляют задуматься о том, «как я могу сделать код тестируемым»? Это должно привести к уменьшению побочных эффектов, упрощению настройки и настройки и т. Д.
Тем не менее, по моему опыту, слишком упрощенные модульные тесты, написанные до того, как вы действительно поймете, каким должен быть проект (по общему признанию, это преувеличение жесткого TDD, но слишком часто программисты пишут тест, прежде чем много думать), приводят к анемии. доменные модели, которые выставляют слишком много внутренних компонентов.
Мой опыт работы с TDD был несколько лет назад, поэтому мне интересно узнать, какие новые методы могут помочь в написании тестов, которые не слишком сильно влияют на базовый дизайн. Спасибо.
источник
Модульное тестирование позволяет увидеть, как работают интерфейсы между функциями, и часто дает представление о том, как улучшить как локальный, так и общий дизайн. Кроме того, если вы разрабатываете свои модульные тесты при разработке кода, у вас есть готовый набор регрессионных тестов. Не имеет значения, разрабатываете ли вы интерфейс или бэкэнд-библиотеку.
После того, как программа разработана (с юнит-тестами), когда обнаружены ошибки, вы можете добавить тесты, чтобы подтвердить, что ошибки исправлены.
Я использую TDD для некоторых своих проектов. Я приложил немало усилий для создания примеров, которые я извлек из учебников или статей, которые считаются правильными, и протестировал код, который я разрабатываю, используя этот пример. Любое недоразумение, которое я имею в отношении методов, становится очень очевидным.
Я склонен быть немного более свободным, чем некоторые из моих коллег, так как мне все равно, будет ли код написан первым или тест написан первым.
источник
Если вы хотите выполнить модульное тестирование вашего синтаксического анализатора, обнаруживающего правильное разграничение значений, вы можете передать его одной строкой из файла CSV. Чтобы сделать ваш тест прямым и коротким, вы можете проверить его одним методом, который принимает одну строку.
Это автоматически заставит вас отделить чтение строк от чтения отдельных значений.
На другом уровне вы можете не захотеть помещать всевозможные физические CSV-файлы в ваш тестовый проект, но сделать что-то более читабельное, просто объявив большую строку CSV внутри своего теста, чтобы улучшить читаемость и цель теста. Это приведет вас к отделению вашего парсера от любого ввода / вывода, который вы бы сделали в другом месте.
Просто базовый пример, просто начните практиковать это, вы почувствуете магию в какой-то момент (у меня есть).
источник
Проще говоря, написание модульных тестов помогает выявить недостатки в вашем коде.
Это впечатляющее руководство по написанию тестируемого кода , написанное Джонатаном Уолтером, Руссом Руффером и Мишко Хевери, содержит многочисленные примеры того, как недостатки в коде, которые препятствуют тестированию, также препятствуют простому повторному использованию и гибкости одного и того же кода. Таким образом, если ваш код тестируемый, его проще использовать. Большая часть «морали» - это смехотворно простые советы, которые значительно улучшают дизайн кода ( Dependency Injection FTW).
Например: очень трудно проверить, правильно ли работает метод computeStuff, когда кеш начинает выдавать вещи. Это связано с тем, что вам нужно вручную добавлять дерьмо в кеш, пока «bigCache» почти не заполнится.
Тем не менее, когда мы используем внедрение зависимостей, гораздо проще проверить, правильно ли работает метод computeStuff, когда кеш начинает выдавать вещи. Все, что мы делаем, это создаем тест, в котором мы называем
new HereIUseDI(buildSmallCache());
Notice, у нас есть более точный контроль над объектом, и он сразу же приносит дивиденды.Аналогичные преимущества могут быть получены, когда нашему коду требуются данные, которые обычно хранятся в базе данных ... просто передайте ТОЧНО те данные, которые вам нужны.
источник
В зависимости от того, что подразумевается под «модульными тестами», я не думаю, что действительно низкоуровневые модульные тесты способствуют хорошему проектированию, а также немного более высокоуровневые интеграционные тесты - тесты, которые проверяют, что группа участников (классов, функций и т. Д.) В Ваш код правильно комбинируется, чтобы создать целую кучу желательных вариантов поведения, которые были согласованы между командой разработчиков и владельцем продукта.
Если вы можете писать тесты на этих уровнях, это подтолкнет вас к созданию красивого, логичного API-подобного кода, который не требует большого количества безумных зависимостей - желание иметь простую настройку теста, естественно, заставит вас не иметь много сумасшедшие зависимости или тесно связанный код.
Не делайте ошибку, хотя - модульные тесты могут привести к плохому дизайну, а также к хорошему дизайну, Я видел, как разработчики берут немного кода, который уже имеет приятный логический дизайн и одну задачу, и разбирают его на части и вводят больше интерфейсов исключительно для целей тестирования, и в результате делают код менее читаемым и трудным для изменения а также возможно даже наличие большего количества ошибок, если разработчик решил, что наличие множества низкоуровневых модульных тестов означает, что им не нужно иметь высокоуровневые тесты. Один из любимых примеров - ошибка, которую я исправил, когда было много разбитого, «тестируемого» кода, связанного с получением и снятием информации в буфере обмена. Все разбито и разделено на очень маленькие уровни детализации, с множеством интерфейсов, множеством издевательств в тестах и другими забавными вещами. Только одна проблема - не было никакого кода, который действительно взаимодействовал бы с механизмом буфера обмена ОС,
Модульные тесты определенно могут повлиять на ваш дизайн, но они автоматически не приведут вас к хорошему дизайну. Вам нужно иметь представление о том, что такое хороший дизайн, который выходит за рамки простого «этот код проверен, поэтому он тестируемый, поэтому он хорош».
Конечно, если вы один из тех людей, для которых «модульные тесты» означают «любые автоматизированные тесты, которые не проходят через пользовательский интерфейс», то некоторые из этих предупреждений могут быть не столь актуальны - как я уже сказал, я думаю, что выше Многоуровневые интеграционные тесты часто являются более полезными, когда речь заходит об управлении вашим дизайном.
источник
Модульные тесты могут помочь с рефакторингом, когда новый код проходит все старые тесты.
Скажем, вы внедрили пузырьковую сортировку, потому что вы спешили и не беспокоились о производительности, но теперь вам нужна быстрая сортировка, потому что данные становятся длиннее. Если все тесты пройдены, все выглядит хорошо.
Конечно, тесты должны быть комплексными, чтобы сделать эту работу. В моем примере ваши тесты могут не охватывать стабильность, потому что это не касается пузырьковой сортировки.
источник
Я обнаружил, что модульные тесты являются наиболее ценными для облегчения долгосрочного сопровождения проекта. Когда через месяцы я возвращаюсь к проекту и не помню многих деталей, проведение тестов не дает мне ломать голову.
источник