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


43

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

Мой вопрос - лучше ли держать модульные тесты в конвейере сборки (таким образом, вводить битые коммиты в репо) или лучше просто не допускать «плохих» коммитов.

Я понимаю, что я не ограничен этими двумя вариантами. Например, я могу разрешить все коммиты разветвленным и тестировать, прежде чем нажать Merge commit для репо. Но если вам придется выбирать между именно этими двумя решениями, какое из них вы выберете и по каким именно причинам?


Ответы:


35

Нет, по двум причинам:

скорость

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

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

Хуже всего то, что вы ничего не можете сделать, чтобы сделать это быстрее. Небольшие проекты Python, которые имеют, скажем, сотню модульных тестов, для запуска на среднем сервере занимают по меньшей мере секунду, но часто гораздо дольше. Для приложения C # это будет в среднем четыре-пять секунд из-за времени компиляции.

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

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

Вместо этого вы можете:

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

    Убедитесь, что найти соответствующие тесты и запустить их на самом деле легко (и быстро). Например, Visual Studio может определить, на какие тесты могут повлиять изменения, выполненные с момента последнего запуска. Другие IDE / платформы / языки / рамки могут иметь аналогичную функциональность.

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

  • Запустите модульные тесты на сервере Continuous Integration.

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

    Например, переход на веб-страницу для проверки последних сборок не является решением. Они должны быть проинформированы автоматически . Отображение всплывающего окна или отправка SMS - два примера того, как они могут быть проинформированы.

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

Безопасность

Сервер, на котором размещено хранилище, не должен запускать пользовательский код, такой как модульные тесты, особенно по соображениям безопасности. Эти причины уже были объяснены в CI Runner на том же сервере GitLab?

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


4
Я согласен, это то, для чего нужен сервер сборки. Ваш источник контроля предназначен для управления исходным кодом, а не для обеспечения работы вашего приложения.
Матфея

4
В крайних случаях ответный удар может быть необходимым инструментом уведомления при взломе сборки.

37
Полсекунды слишком медленно? Это капля в море по сравнению с тем, чтобы дать один последний взгляд на то, что коммитится, а затем подумать и набрать соответствующий комментарий коммита.
Доваль

5
@Doval: разница в том, что когда вы в последний раз смотрите или думаете о комментарии, вы активны , поэтому вы не ждете. Важно не время, которое вы тратите до того, как наберете последний символ в вашей IDE, а время, когда вы можете начать печатать снова после завершения фиксации, но сколько вы ждете. Вот почему компиляторы должны быть быстрыми; Неважно, что вы тратите гораздо больше времени на чтение и написание кода, потому что когда вы делаете это, вы не ждете, тогда как когда код компилируется, у вас возникает соблазн переключиться на другую деятельность.
Арсений Мурзенко

10
@Thomas: дело не в отвлечении, а в раздражении. Точно так же 100 мс. «оказывает ощутимое влияние» на то, как люди используют веб-сайт. Та же картина здесь: 100 мс. ничто по сравнению с тем временем, которое вы тратите на просмотр видео на YouTube или запуск своего ПК: сознательно вы не заметите разницу между 600 мс. и 700 мс. задержка. Но неосознанно это влияет на ваше поведение. Таким же образом, немного более медленные коммиты отговаривают вас от коммитов рано и часто.
Арсений Мурзенко

41

Позвольте мне быть тем, кто не согласен с моими коллегами-ответчиками.

Это известно как Gated Check-in в мире TFS, и я ожидаю в другом месте. Когда вы пытаетесь выполнить возврат в филиал с помощью gated-регистрации, набор полок отправляется на сервер, который обеспечивает сборку ваших изменений и выполнение указанных (прочитанных: всех) модульных тестов. Если они этого не делают, он уведомляет вас, что вы плохая обезьяна, которая сломала сборку. Если они это сделают, изменения перейдут в систему контроля версий (ууу!).

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

Зачем?

  • Потому что закрытые проверки заставляют людей исправлять испорченные тесты. Как только сломанные тесты становятся чем-то, что люди могут делать, а не должны делать, они становятся приоритетными для ленивых инженеров и / или настойчивых бизнесменов.
    • Чем дольше тест пройден, тем сложнее (и дороже) его исправить.
  • Потому что как только люди должны проводить тесты , а не должны запускать тесты, запуск тестов обходят ленивыми / забывчивость инженеров и / или настойчивых деловых людей.
  • Потому что, как только модульные тесты влияют на ваше время фиксации, люди действительно начинают заботиться о том, чтобы делать свои тесты модульными тестами. Скорость имеет значение. Воспроизводимость имеет значение. Надежность имеет значение. Изоляция имеет значение.

И, конечно, вы извлекли выгоду изначально - когда у вас есть закрытые регистрации и солидный набор тестов, каждый набор изменений «стабилен». Вы сохраняете все эти накладные расходы (и потенциальную возможность ошибки) на «когда была последняя хорошая сборка?» - все сборки достаточно хороши, чтобы развиваться против.

Да, для сборки и запуска тестов требуется время. По моему опыту 5-10 минут для хорошего приложения C # и ~ 5k юнит-тестов. И мне все равно. Да, люди должны часто регистрироваться. Но они также должны часто обновлять свои задачи, или проверять свою электронную почту, или получать кофе или десятки других «не работающих над кодом» вещей, которые составляют работу разработчика программного обеспечения, чтобы занять это время. Проверка плохого кода обходится намного дороже, чем 5-10 минут.


3
+1 Я хочу добавить, что многие проекты с открытым исходным кодом имеют четкое различие между вкладом и обязательством. Причины этого очень похожи на то, почему существуют закрытые проверки.
JensG

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

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

@ Telastyn– Shelvesets - новый термин для меня. Я понимаю, что это опция MS VS, которая не подходит для огромного количества проектов. В области разработки мобильных приложений VS не является игроком.
CuriousRabbit

3
@CuriousRabbit - правда? Команда, распределенная в течение 17 часов, больше заботится о 10-минутном ожидании коммита, чем о возможности неработающей сборки, пока нарушитель спит? Это кажется ... менее чем оптимальным.
Теластин

40

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

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

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

Я также должен отметить, что в некоторых интерпретациях Test Driven Development следует проверять модульный тест, который сначала ломается . Это демонстрирует и документирует наличие ошибки. Тогда более поздняя регистрация будет кодом, который исправляет юнит-тест. Предотвращение любых проверок до прохождения модульных тестов уменьшит эффективное значение проверки в модульном тесте, который не документирует проблему.

Связанный: Должны ли я иметь модульные тесты для известных дефектов и какова ценность проверки при неудачных юнит-тестах?


2
Commits should run fast.Каковы преимущества этого? Мне любопытно, потому что мы в настоящее время используем закрытые проверки. Обычно мои проверки - это кумуляция часа или около того работы, так что 5-минутное ожидание не имеет большого значения. На самом деле я обнаружил , что его , как правило те времена , когда я нахожусь в спешке , что сборка проверка является наиболее полезным для ловли глупых ошибок (в результате стремительного движения)
Джастин

1
@Justin Пятиминутное ожидание - это пятиминутное ожидание, где бы оно ни было. Один не нужно , чтобы вырваться NERF мечи каждый раз , когда вы фиксации. И я нередко делю час или около того работы на несколько коммитов, которые являются концептуальными единицами друг друга - «фиксировать код службы отдыха», а затем «фиксировать код для обслуживаемой клиентской страницы» как две отдельные фиксации. (не говоря уже о твике css как о другом коммите). Если для выполнения каждого из них потребовалось 5 минут, 1/6 моего времени тратится на ожидание тестов. Это привело бы к большим

5 минут ждать, чтобы запустить модульные тесты? Я чувствую, что проекты, над которыми вы работаете, должны быть разбиты на более мелкие компоненты.
user441521

@ catching silly mistakes (as a result of rushing)Точно так же. спешка вообще плохая практика в разработке программного обеспечения. Роберт К. Мартин рекомендует писать код, например, делать операцию youtube.com/watch?v=p0O1VVqRSK0
Джерри Джозеф,

10

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

Тем не менее, конкретное решение коммитов не является хорошим планом.

  1. Разработчик должен дождаться запуска тестов во время фиксации. Если разработчику приходится ждать на своей рабочей станции всех тестов для прохождения, вы теряете драгоценное инженерное время. Инженер должен иметь возможность перейти к следующему заданию, даже если ему придется вернуться назад, потому что тесты закончились неудачей.
  2. Разработчики могут захотеть зафиксировать испорченный код в ветке. В более крупной задаче версия кода для разработчиков может проводить много времени не в состоянии прохождения. Очевидно, что объединить этот код с основной строкой было бы очень плохо. Но довольно важно, что разработчик все еще может использовать контроль версий для отслеживания своего прогресса.
  3. Иногда есть веские причины пропустить процесс и обойти тесты.

2
# 1 устраняется, позволяя разработчикам регистрироваться в личном филиале или локальном хранилище. Только когда разработчик хочет где-то свой код, другие разработчики могут увидеть его, чтобы запустить модульные тесты. Как и с № 1, № 2 устраняется только зацепками к ветвям магистрали. № 3 устраняется тем фактом, что A) Любая такая функция может быть отключена, даже если это хлопотно (и должно быть хлопотно) и B) Отдельные неудачные юнит-тесты могут быть отключены.
Брайан

@ Брайан, я полностью согласен, ты можешь сделать эту работу. Но попытка сделать это путем блокировки коммита на стороне сервера не сработает.
Уинстон Эверт

хорошие моменты. Breaking the build is simply too costly in terms of lost time for all engineers on the projectЯ бы предложил использовать какой-нибудь инструмент для уведомления о сборке, чтобы избежать потери всеми инженерами времени на каждую сломанную сборку
Джерри Джозеф

3

Нет, вы не должны, как указывали другие ответы.

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


2

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

Но есть и другие способы достижения последовательной основной ветки. Вот одно предложение, немного похожее в плане стробированных проверок в TFS, но которое можно обобщить для любой системы контроля версий с ветвями, хотя я в основном буду использовать термины git:

  • Создайте промежуточную ветку, в которую вы можете фиксировать только слияния между вашими ветками разработчика и основной веткой

  • Установите хук, который запускает или ставит в очередь сборку и тестирует коммиты, сделанные в промежуточной ветке, но это не заставляет коммиттера ждать

  • При успешной сборке и тестировании автоматически заставьте основную ветвь идти вперед, если она обновлена

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

Как следствие:

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

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

  • Вам придется выбирать между:

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

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

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

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

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

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

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

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


Но суть в том, чтобы иметь рабочую ветвь (обычно) не в том, чтобы обеспечить стабильный выпуск, а в том, чтобы сократить побои, вызванные разработчиками, работающими вместе в одном коде.
Теластин

Нет, если у вас огромный репо с большими, глобально распределенными командами. Например, Microsoft использует похожий, более многоуровневый подход с Windows.
acelen

2

Я предпочитаю, чтобы «пройденные модульные тесты» были воротами для отправки кода. Однако, чтобы это работало, вам понадобится несколько вещей.

Вам понадобится сборочный фреймворк, который кэширует артефакты.

Вам понадобится тестовая структура, которая кэширует статус теста из (успешных) тестовых прогонов с любым заданным артефактом (ами).

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


1

Я бы сказал, что это зависит от проекта и объема автоматизированных тестов, которые выполняются на коммите.

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

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

Вы пишете «commit ... to remote branch» в вопросе, что для меня означает, что (а) не то, что разработчик делает каждые несколько минут, поэтому небольшое ожидание может быть очень приемлемым, и (б) что после При такой фиксации изменения кода могут повлиять на других разработчиков, поэтому могут потребоваться дополнительные проверки.

Я могу согласиться с другими ответами о том, что «не заставляйте своих разработчиков вертеться во время ожидания» для такой операции.


1

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

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

Некоторые примеры:

  • В TDD, как правило, перед началом реализации этой функции передают и отправляют неудачные тесты для новых функций.
  • То же самое касается сообщения об ошибках путем фиксации и проверки неудачного теста.
  • Выдвижение неполного кода позволяет двум или более людям легко работать над функцией параллельно
  • Ваша инфраструктура CI может занять время проверки, но разработчику не нужно ждать
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.