Подтвердить что ты не робот

Проверяемые единицы измерения

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

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

Итак, есть ли какие-нибудь хиты/советы для написания поддерживаемого кода TDD? Я сейчас читаю Roy Osherove The Art Of Unit Testing, есть ли другие ресурсы, которые могли бы помочь мне?

Спасибо

4b9b3361

Ответ 1

практика

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

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

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

Некоторые советы, которыми я живу, следуют правилу AAA.

Устройся, действуй и утверждай. Каждый тест должен следовать этой формуле. Это делает тест читаемым, и его легко поддерживать, если и когда он ломается.

Дизайн по-прежнему важен

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

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

Посетите блог тестирования Google - это был поворотный момент для меня при запуске TDD. Статьи Misko (и сайт - особенно руководство по тестируемому коду) превосходны и должны указывать вам правильное направление.

Ответ 2

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

Так? Как это проблема?

Ваши требования изменились. Это означает, что ваш дизайн должен был измениться. Это означает, что ваши тесты должны были измениться.

"Я потратил больше времени на переписывание/исправление модульных тестов, чем написание кода, на самом деле гораздо больше времени".

Это означает , что вы делаете это правильно. Требования, дизайн и тестовое воздействие были в тестировании, и ваше приложение не требовало больших изменений.

То, как он должен работать.

Иди домой счастливым. Вы правильно выполнили работу.

Ответ 3

Im огромный поклонник модульного тестирования, но у меня возникли проблемы с TDD (или базовым модульным тестированием в этом отношении) в моем последнем проекте. После проведения обзора после внедрения я обнаружил, что мы (я и остальная часть команды) столкнулись с двумя основными проблемами с нашей реализацией/пониманием TDD и модульного тестирования.

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

Когда мы смотрим немного глубже на неудачные модульные тесты, мы обнаружили, что мы слишком много тестировали, особенно учитывая наши временные ограничения. Вместо того, чтобы использовать TDD и фокусировать наше тестирование на коде с высокой отдачей, мы использовали TDD и записывали тесты для всей базы кода. Это сделало нашу долю единичных тестов намного лучше, чем мы могли бы поддерживать. Мы (в конечном итоге) решили использовать TDD и писать тесты для бизнес-функций, которые могут измениться. Это уменьшило нашу потребность в поддержании большого количества тестов, которые по большей части очень редко (или никогда) не менялись. Вместо этого наши усилия были более целенаправленными и сделаны для более полного набора тестов по тем частям приложения, о которых мы действительно заботились.

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

Ответ 4

Похоже, ваши юнит-тесты хрупки и накладываются друг на друга. Единственное изменение кода, в идеале, должно затрагивать только один unit test - с индивидуальным соответствием тестов для функций, другие тесты не зависят от данной функции. Это может быть слишком идеалистичным; на практике многие из наших тестов повторно используют один и тот же код, но это что-то, о чем нужно помнить. Когда одно изменение кода влияет на многие тесты, это запах. Кроме того, в отношении вашего конкретного примера переименования: найдите инструмент, который будет автоматизировать эти рефакторинги для вас. Я считаю, что Resharper и CodeRush поддерживают такие автоматические рефакторинги; это гораздо более быстрый, простой и надежный способ рефакторинга, чем ручной подход.

Чтобы лучше узнать вашу среду IDE, ничто не сравнится с кем-то другим. Вы оба научитесь; вы будете развивать новые навыки - и это не займет много времени. Несколько часов значительно увеличит ваш комфорт с помощью инструмента.

Ответ 5

Да, есть целая книга под названием xUnit Test Patterns, посвященная этой проблеме.

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

В любом случае, суть в том, что вы должны относиться к своему тестовому коду так же, как к рабочему коду. Прежде всего, вы должны придерживаться принципа СУХОЙ, потому что это упрощает рефакторинг вашего API.

Ответ 6

Вы используете либеральное использование интерфейсов, Injection Dependancy Injection и насмехаетесь?

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

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

Ответ 7

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

Когда я запускаю проект, так как требования и цели меняются все время, я почти ничего не пишу вообще, потому что, как вы заметили, потребуется много времени для постоянного исправления тестов. Некоторое время я просто пишу в комментарии "это должно быть проверено", поэтому я не забуду его протестировать.

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

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

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

Ответ 8

Прежде всего, Refactoring не прерывает модульные тесты. Вы применили рефакторинг книгу? Может быть, ваши тесты проверяют реализацию, а не поведение, что может объяснить, почему они ломаются.

Тестирование модулей должно быть тестированием черного ящика, проверить, что делает устройство, а не как оно это делает.

Ответ 9

Я нашел полуавтоматический инструмент тестирования разработчика для Java с именем SpryTest. Он обеспечивает простой, но мощный пользовательский интерфейс для создания рандомизированных данных. Он также поддерживает насмешливые звонки с использованием powermock и easymock. Он может генерировать стандартные тесты JUnit, которые ближе всего подходят для письменных тестов вручную. Он имеет функцию проверки подлинности исходного кода.

Пробовал и работал очень хорошо для меня. Проверьте инструмент http://www.sprystone.com

Ответ 10

Вы используете хорошую среду IDE? Я задавал себе тот же вопрос, что и вы, несколько лет назад, когда я впервые обнял Unit Testing. Тогда я использовал комбинацию Emacs, find и grep для рефакторинга. Было больно.

К счастью, коллега побил меня по голове и убедил меня попробовать "современные инструменты", которые в его народном языке означали Intellij IDEA, IDEA - мое личное предпочтение, но Netbeans или Eclipse будут обрабатывать основы так же хорошо. Мне трудно переоценить прирост производительности, который мне предоставлял; легко получить прирост порядка, особенно для крупных проектов с большим количеством тестов.

Когда у вас есть IDE в квадрате, если вы все еще сталкиваетесь с проблемами, пришло время рассмотреть принцип

Ответ 11

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

Рассмотрим определение обязанностей класса в качестве вызовов, которые он вносит в инъецируемый интерфейс. Подумайте об этом больше с точки зрения передачи данных или отправки сообщения, а не для управления состоянием.