Какой смысл проводить модульные тесты на CI-сервере?

98

Зачем вам запускать модульные тесты на CI-сервере?

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

Стив
источник
51
Наши разработчики не имеют права совершать мастеринг. Они переходят к ветви функций, затем сервер CI сливается с master и запускает тесты. Если они успешны, то изменения объединяются с мастером. Так что код с испорченными тестами не может быть на хозяине ...
Борис Паук
2
@BoristheSpider - действительно очень хороший рабочий процесс. masterдолжен всегда быть в здравом уме, и предпочтительно автоматически развертываться при каждом слиянии с промежуточной средой для внутреннего контроля качества и тестирования.
За Лундберг
130
«Конечно, к тому времени, когда что-то будет передано мастеру, разработчик уже выполнил все модульные тесты и исправил все ошибки, которые могли произойти с их новым кодом». В каком фэнтезийном мире вы живете?
jpmc26
5
В некоторых отраслях важной частью является не только запуск тестов в коде, но и запуск тестов в двоичных файлах . Выполнение тестов на выходе CI означает, что вы можете гарантировать, что поставленный продукт работает, потому что именно тот двоичный файл, который получил ваш клиент, является тем, который прошел все ваши тесты. Это звучит тривиально, но иногда это может иметь эффект (один из тех, что я видел, это запутывание; в сложных проектах или при странной настройке это может вызвать проблемы в запутанной сборке, которых не было в чистой версии).
Анаксимандр
5
«Конечно, к тому времени, когда что-то передается мастеру, разработчик уже выполнил все модульные тесты и исправил все ошибки, которые могли произойти с их новым кодом.» ... не уверен, если серьезно
chucksmash

Ответы:

224

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

Или нет. Может быть много причин, почему это может произойти:

  • Разработчик не имеет дисциплины, чтобы сделать это
  • Они забыли
  • Они не зафиксировали все и выдвинули неполный набор коммитов (спасибо Мэтью М.
  • Они только выполнили некоторые тесты, но не весь набор (спасибо nhgrif )
  • Они тестировали на своей ветке до слияния (спасибо nhgrif * 2)

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

Это помогает выявить проблемы, когда тесты и / или код зависят от чего-то определенного для блока разработчика (конфигурация, данные, часовой пояс, локаль и т. Д.).

Другие веские причины для сборки CI для запуска тестов:

  • Тестирование на разных платформах, кроме основных платформ разработки, что может быть затруднительно для разработчика. (спасибо TZHX )
  • Приемка / интеграция / сквозное тестирование / действительно длительные тесты могут выполняться на сервере CI, который обычно не запускается на компьютере разработчика. (спасибо Ixrec )
  • Разработчик может внести незначительное изменение перед тем, как нажать / подтвердить (думая, что это безопасное изменение и поэтому не запускает тесты). (спасибо Ixrec * 2)
  • Конфигурация CI-сервера обычно не включает в себя все инструменты разработчика и конфигурацию и, следовательно, ближе к производственной системе.
  • Системы CI создают проект с нуля каждый раз, что означает, что сборки повторяются
  • Смена библиотеки может вызвать проблемы в нисходящем направлении - CI-сервер может быть настроен на создание всех зависимых кодовых баз, а не только библиотечной
Одед
источник
36
Другие распространенные причины: 1) CI-сервер может запускать высокоуровневые интеграционные / приемочные тесты, которые отнимают у разработчиков слишком много времени. 2) Разработчик запустил их, а затем внес одно маленькое изменение, прежде чем заявить, что они уверены, что ничего не сломает, но мы хотим быть уверены.
Ixrec
11
Изменение зависимости часто также запускает все последующие сборки. Если изменение, которое вносит разработчик, нарушает что-то в нисходящем направлении, это не так легко увидеть при изменении библиотеки (скажем, при изменении базового типа данных с SortedSet на HashSet (только с предоставлением контракта Set)), и кто-то в нисходящем потоке работал над ошибочным предположением, что Набор был отсортирован). Отсутствие (нисходящих) тестов на CI-сервере позволит этой ошибке на некоторое время нарастать.
2
@MichaelT Хороший улов. Это на самом деле причина для> 90% наших сбоев CI в наши дни, не знаю, как я это забыл ...
Ixrec
34
Кроме того, запуск их в среде CI обычно означает, что вы настраиваете проект с нуля , обеспечивая повторяемость сборки .
mgarciaisaia
5
Кроме того, могут быть зафиксированы два изменения, которые тестируются нормально по отдельности, но разбиваются вместе (например, одно удаляет неиспользуемый API, а другое начинает его использовать).
Саймон Рихтер
74

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

Я должен был бы построить, проверить и проверить, что приложение работает правильно на:

  • Microsoft Windows XP и Vista с компилятором Visual Studio 2008.
  • Microsoft Windows 7 с компилятором Visual Studio 2010.
    • Да, и MSI собирает для каждого из них.
  • RHEL 5 и 6 с 4.1 и 4.4 соответственно (аналогично CentOS)
    • 7 скоро. Woop-де-Woop.
  • Рабочая станция Fedora с GCC для последних трех последних версий.
  • Debian (и его производные, такие как Ubuntu) для последних трех последних версий.
  • Mac OSX в последних трех последних версиях.
    • И пакеты (RPM, DMG и т. Д.)

Добавьте в Fortran (с компиляторами как Intel, так и GNU) Python (и его различные версии в зависимости от ОС) и компоненты сценариев bash / bat, и, я думаю, вы можете видеть, что все идет по спирали

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

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

TZHX
источник
3
Модульное тестирование тестирует код, а не конфигурации. Было бы серьезно инертно с вашей стороны добавить новый тест и перебросить его через стену, даже не запустив его сначала локально ...
Робби Ди
33
@RobbieDee Боюсь, я не вижу твоей точки зрения? Я не предлагаю создавать новые тесты, не тестируя их локально, или просто слепо вводить объекты в систему контроля версий, не тестируя их самостоятельно, и я бы запускал тесты на своей собственной машине, но «конфигурация» должна быть проверена на согласованное поведение и лучше сделать это сравнительно быстро, когда разработчик все еще находится в этой области, чем найти проблему, когда команда, которая преимущественно использует Mac, просыпается на расстоянии четырех тысяч миль и обновляет свои копии.
TZHX
7
@RobbieDee Я бы сказал, что TZHX будет запускать все тесты локально, если они смогут, но не могут . Поскольку TZHX не может, они запускают некоторые тесты локально (например, те, которые могут выполняться в их системе разработки и достаточно короткие или наиболее релевантные измененному коду), и позволяют полной батарее работать в системе CI. Довольно разумно
Муру
11
@RobbieDee: Он верит в модульное тестирование. Поэтому он тестирует их на своем Macbook и передает и регистрирует. Серверы CI, работающие под управлением Red Hat, Solaris и Windows, затем снова запускают эти тесты. Разве не приятно знать, что то, что вы тестировали, также работает на производственных платформах?
Slebetman
2
@RobbieDee: Я часто писал модульные тесты, которые были характерны для определенного компилятора на определенной платформе. Рассмотрим, например, графическую подсистему, которая использует специфичные для AMD (конкурента Intel) инструкции процессора, которые доступны только в g ++ (компилятор GNU C ++) версии 4.5 или новее, но мне довелось работать на процессоре Atom и ICC (Intel C ++). Compiler). Было бы бессмысленно каждый раз запускать тесты AMD / g ++ 4.5 на этой машине, но это код, который нужно протестировать перед выпуском; плюс мой собственный независимый от процессора код должен быть проверен на правильную совместимость. Конечно, есть виртуальные
машины
23

Помимо превосходного Одеда ответ:

  • Вы тестируете код из репозитория . Он может работать на вашей машине с вашими файлами ... которые вы забыли зафиксировать. Это может зависеть от новой таблицы, в которой нет сценария создания (например, в liquibase), некоторых данных конфигурации или файлов свойств.
  • Вы избегаете проблем с интеграцией кода. Один разработчик загружает последнюю версию, создает модульное и интеграционное тестирование, добавляет код, проходит все тесты на своем компьютере, фиксирует и запускает. Другой разработчик только что сделал то же самое. Оба изменения правы сами по себе, но при объединении вызывает ошибку. Это может быть слияние репозитория или просто то, что оно не определяется как конфликт. Например, Dev 1 удаляет файл, который вообще не использовался. Dev 2 кодирует этот файл и тестирует без изменений Dev 1.
  • Вы разрабатываете скрипт для автоматического развертывания из репозитория. Наличие универсального сценария сборки и развертывания решает множество проблем. Некоторые разработчики могли добавить библиотеку или опцию компиляции, которая доступна не всем. Это не только экономит ваше время, но, что более важно, делает развертывание безопасным и предсказуемым. Кроме того, вы можете вернуться в свой репозиторий до версии 2.3.1 и развернуть эту версию со скриптом, который работает с этой версией. Он включает объекты базы данных, такие как представления, хранимые процедуры, представления и триггеры, которые должны быть версионными. (Или вы не сможете вернуться к работоспособной версии).
  • Другие тесты : как интеграция, производительность и сквозные тесты. Это может быть медленно и может включать инструменты тестирования, такие как Selenium. Вам может понадобиться полный набор данных с реальной базой данных вместо фиктивных объектов или HSQL.

Однажды я работал в фирме, у которой было много ошибок при развертывании из-за процесса слияния и развертывания. Это было вызвано странной пропиетической структурой, которая усложнила тестирование и КИ. Было не очень приятно, что код, который отлично работал при разработке, не попал прямо в производство.

Borjab
источник
Да, просто забыть совершить некоторые изменения очень часто. Я бы сказал, забыв «добавить svn» новые файлы, и забыв зафиксировать их позже, это самый популярный способ получить неудачную автоматическую сборку.
Sharp Bluetooth
22

Вы бы так подумали, но разработчики - люди, и они иногда забывают.

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

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

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

Робби Ди
источник
7
Я видел больше упс, я забыл совершить ошибки CI, которые я хочу признать.
Дэн Нили,
@DanNeely Чтобы быть справедливым, это лучше, чем получить задницу от менеджера сборки, потому что вы забыли рассказать ему / ей о чем-то ... :-)
Робби Ди
3
Это одна из причин, по которой я люблю КИ. Поиск и исправление ваших собственных проблем гораздо лучше, чем когда кто-то другой найдет их для вас.
Дэн Нили,
14

к тому времени что-то становится совершенным

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

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

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

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

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

Daenyth
источник
1
У вас не должно быть медленных юнит-тестов - это нарушает принципы FIRST .
Робби Ди
4
@RobbieDee: Я думаю, что обычно CI-сервер выполняет все тесты, а не только юнит-тесты.
RemcoGerlich
4
@RobbieDee: теоретически все юнит-тесты выполняются быстро. На практике .... Независимо от этого, CI может и должен выполнять все тесты - линтеры, статический анализ, модульные тесты, интеграционные тесты.
Дейнит
2
@RobbieDee Очевидно, что особенности конфигурации будут отличаться от команды к команде. Даже если сборка занимает несколько минут, часто можно запустить несколько таких сборок параллельно. Учитывая одну монолитную кодовую базу, это может быть большим недостатком, но IME это не барьер.
Daenyth
1
@RobbieDee Я думаю, это зависит больше от вашей архитектуры. Я видел, что это работает на руку для команды инженеров ~ 80, но это с четко определенными подгруппами для областей продукта.
Daenyth
4

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

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

Дэвид Арно
источник
3

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

  • Выполнение юнит-тестов может занять много времени для некоторых специальных настроек. Например, выполнение модульных тестов с помощью средства проверки памяти (например, valgrind) может занять гораздо больше времени. Хотя все модульные тесты проходят, проверка памяти может не пройти.
  • результат не так важен для некоторых специальных настроек - например, запуск модульных тестов для проверки покрытия кода требует специальных флагов компиляции. Для обычных разработчиков охват кода не так важен - для людей, которые заботятся о том, чтобы код поддерживал определенное качество, как, например, руководителям команд, важнее.
BЈовић
источник
3

Можно представить себе случаи, когда изменение A не нарушает тест, а изменение B не нарушает тест, но A и B вместе делают. Если A и B сделаны разными разработчиками, только CI-сервер обнаружит новую ошибку. А и В могут даже быть двумя частями одного и того же более длинного предложения.

Представьте себе поезд, которым управляют два локомотива A и B. Может быть, одного более чем достаточно, и это исправление для применения. Однако если применить два «исправления», удалив оба, поезд не будет двигаться.

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

h22
источник
2

Давайте зададим эквивалентный вопрос:

Зачем вам создавать код на CI-сервере?

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


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

Если код никогда не нарушается, почему мы вообще используем CI? Чтобы доставить сборки для тестирования, ночных сборок будет достаточно.

Питер
источник