TDD и контроль версий

25

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

  1. Я начинаю новый проект и пишу простой тест для создания еще не существующего класса. Должен ли я выполнить тест перед написанием класса, даже если тест даже не компилируется? Или я должен заглушить минимальный объем кода, необходимый для компиляции теста перед его фиксацией?

  2. Я нахожу ошибку и пишу тест, чтобы воссоздать ее. Должен ли я выполнить неудачный тест или реализовать исправление ошибки, а затем зафиксировать?

Это два примера, которые сразу приходят на ум. Не стесняйтесь приводить дополнительные примеры в своем ответе.

Редактировать:

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

Это означает, что мой вопрос касается как того, что совершать, так и вопроса о том, когда совершать.

Код-Guru
источник

Ответы:

21

Должен ли я выполнить тест перед написанием класса, даже если тест даже не компилируется? Или я должен заглушить минимальный объем кода, необходимый для компиляции теста перед его фиксацией?

Конечно нет. Вы должны закончить и тест, и класс. Записывать что-то 1, что даже не компилируется, не имеет смысла, и, конечно, люди, работающие над одним и тем же проектом, будут сердиться, если вы будете делать это регулярно.

Я нахожу ошибку и пишу тест, чтобы воссоздать ее. Должен ли я выполнить неудачный тест или реализовать исправление ошибки, а затем зафиксировать?

Нет, не совершайте провальный тест. Закон Леблана гласит:

Позже равных никогда.

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

Также стиль разработки TDD говорит:

Разработка через тестирование постоянно повторяет этапы добавления тестовых примеров, которые не пройдены, их прохождение и рефакторинг.

Если вы проверите несостоявшийся тест, это означает, что вы не завершили цикл.


1 Когда я сказал commit, я имел в виду действительно commit для trunk (для пользователей git проталкивайте свои изменения, чтобы другие разработчики могли их получить).

BЈовић
источник
4
«и, несомненно, заставит злых людей работать над одним проектом, если» - кто-то, живущий в мире SVN, использует GIT, и вы никого не оскорбите
Mateusz
3
Я думаю, что после написания теста все в порядке, просто не настаивайте, пока не закончите.
Мацеманн
4
@radarbob Это относится даже к DVCS, где есть различие между фиксацией и нажатием? Я могу представить себе ситуацию, когда я делаю несколько коммитов в локальном git-репо, когда при финальном коммите сборка не нарушается, но при любом временном коммите это может быть.
Code-Guru
6
Нет, не совершайте неудачный тест. Но один из пунктов TDD состоит в том, чтобы сделать неудачный тест перед кодированием. Так что совершение неудачного теста имеет смысл.
Мувициэль
4
@ Code-Guru: Для DVCS такие правила должны быть такими: «Не передавайте испорченный код в ветку, из которой регулярно извлекаются другие». Если другие не вытянут из вашего локального репо, то это может быть в любом состоянии, с которым вы можете жить.
Барт ван Инген Шенау
6

Должен ли я выполнить тест перед написанием класса, даже если тест даже не компилируется?

Нет.

Должен ли я совершить провальный тест

Нет.

Вы говорите о двух парадигмах здесь:

  1. разработка через тестирование, которая ничего не говорит о фиксации кода. Действительно, он говорит вам о том, как писать код и когда вы закончите. Поэтому я бы рассматривал каждое «готово» в качестве кандидата на коммит.
  2. гибкая разработка, а именно: «совершать рано и часто» (что не требует TDD). Идея заключается в том, чтобы обеспечить раннюю интеграцию с другими компонентами системы и, таким образом, получить раннюю обратную связь. Если вы фиксируете в DVCS локально и не продвигаетесь, это бесполезно в этом смысле. Местные коммиты только помогают разработчикам структурировать свою работу.

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

Для большого исправления фиксируйте после каждого улучшения (например, рефакторинг), даже если ошибка еще не исправлена. Тесты должны быть зелеными, а код должен компилироваться.

Энди
источник
5

Конечно, вы начинаете с использования здорового исходного кода, такого как git.

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

Затем, перед тем как добавить материал, вы сводите всю работу в один коммит. Или пара, в точках, где все зелено и композиция имеет смысл. И подтолкнуть эти разумные коммиты. Для нескольких случаев сделайте это ветвью, которую вы объединяете с --no-ff.

Источник контроля не является системой отслеживания работы или историком. В коммитах должна быть представлена ​​разумная когерентная дельта, в то время как состояние проверки должно составлять как минимум. Промежуточные звенья могут быть сохранены на некоторое время для ознакомления, но как только все будет в порядке, один коммит для каждой функции будет справедливым.

Балог Пал
источник
5

В моем понимании мира человек обязуется отметить точку, к которой, возможно, было бы желательно вернуться. Точка a, в которой тест не пройден (но компилируется), определенно является одной из таких точек. Если бы мне пришлось отклониться в неверном направлении, пытаясь пройти тест, я хотел бы иметь возможность вернуть код обратно в исходную точку и повторить попытку; Я не могу сделать это, если я не совершил.

Scroog1
источник
Я согласен. Я предпочитаю использовать другую ветку, чтобы следовать правилу «не нарушать сборку» и объединять изменения в стволе только после прохождения теста.
Fil
5

Должен ли я выполнить тест перед написанием класса, даже если тест даже не компилируется?

С разветвленной SCM (я видел, что вы используете Git) вы должны фиксировать всякий раз, когда вам нужна точка резервного копирования («Я что-то испортил; я сброслю рабочий каталог до последней точки резервного копирования») или когда у вас стабильная версия. Если у вас стабильная версия (все тесты пройдены), вам также следует рассмотреть возможность слияния текущей функциональной ветви с основной веткой разработки.

Или я должен заглушить минимальный объем кода, необходимый для компиляции теста перед его фиксацией?

На ваше усмотрение (git дает вам гибкость, позволяющую совершать коммиты в любое время, не затрагивая других членов вашей команды, или вашу способность работать с различными функциями). Просто убедитесь, что у вас нет нескольких незавершенных (нерабочих) функций в одной ветви одновременно (тогда они будут блокировать друг друга).

Я нахожу ошибку и пишу тест, чтобы воссоздать ее. Должен ли я выполнить неудачный тест или реализовать исправление ошибки, а затем зафиксировать?

Я обычно делаю для этого два коммита, если только тестовый код не слишком мал / тривиален для написания.

Это два примера, которые сразу приходят на ум. Не стесняйтесь приводить дополнительные примеры в своем ответе.

Редактировать:

В обоих примерах я сделал предположение, что сразу после написания теста напишу код для прохождения теста.

Это может быть неправильным предположением. Если вы работаете один (личный проект), ничто не мешает вам всегда делать это. В одном из моих самых успешных проектов (в отношении поддержания высокого качества кода и TDD на протяжении всей разработки проекта) мы определяли тесты иногда за несколько недель до их реализации (то есть мы бы сказали, что «тест« test_FOO_with_null_first_parameter »теперь определен как пустая функция и зафиксируйте это так). Затем мы бы взяли спринт (или половину спринта) иногда через месяц или около того, чтобы просто увеличить охват тестами для модуля. Так как у нас уже были объявлены тесты, это было легко оценить.

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

Я бы сказал, определенно обязуюсь создавать резервные точки . Это очень хорошо работает для исследовательского тестирования («я просто добавлю несколько распечаток по всей базе кода, запуском и git reset --hardудалением их, когда я закончу) и для прототипирования.

utnapistim
источник
2
Будьте осторожны с рекомендациями git reset --hard. Это одна из немногих команд в git, которая заставит вас потерять работу.
gnash117
2

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

С точки зрения TDD, вопрос «Вы сначала проходите тестирование?» полностью зависит от кода, над которым вы работаете. Если это новый код, вы ничего не регистрируете, пока не найдете что-то стоящее. Но если это ошибка, обнаруженная в уже скомпилированном или поставленном коде, стоит проверить в тесте, чтобы воспроизвести ошибку, ПО СЕБЕ, стоит проверить. Особенно, если это конец рабочего дня, и вы покинете офис до того, как исправите код.

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

DougM
источник