Автоматизированное модульное тестирование, интеграционное тестирование или приемочные испытания [закрыто]

29

TDD и модульное тестирование в настоящий момент являются самым восторженным событием. Но действительно ли это полезно по сравнению с другими формами автоматизированного тестирования?

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

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

Или, может быть, модульное тестирование просто дает наибольший выигрыш по сравнению со сложностью его автоматизации?

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

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

Заранее спасибо.

Бьярке Фрейнд-Хансен
источник
Я просто хотел бы добавить запоздалую ссылку на Интеграционные тесты JB Rainsberger Are A Scam . В нем подчеркиваются многие причины, по которым интеграционные тесты являются ложной экономией.
Тим
1
Проверьте следующие относительные ссылки: stackoverflow.com/questions/437897/… stackoverflow.com/questions/520064/… stackoverflow.com/questions/4904096/…
CodyChan
6
Это еще один пример закрытия вопроса, который был прекрасно на этом сайте, когда его задавали три года назад! Это действительно раздражает, чтобы внести свой вклад в сообщество, где правила меняются, и вы просто выбрасываете все старые вещи!
Бьярке Фрейнд-Хансен

Ответы:

34

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

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

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

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

В то время как в модульном тестировании (TDD)

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

Все это происходит в считанные минуты .

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

Не говоря уже о том, что модульное тестирование также проверяет ваши интерфейсы на удобство использования / безопасность и т. Д., Что дает вам жизненно важную обратную связь для улучшения вашего дизайна и API. ИМХО может значительно снизить шансы ошибок интеграции модуля / подсистемы: чем проще и чище API, тем меньше вероятность недопонимания или упущения.

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

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

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

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

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

Петер Тёрёк
источник
2
+1 за «быструю обратную связь» за юнит-тесты. Также очень удобно для работы в качестве пост-коммита на сервере Continuous Integration.
Фрэнк Шиарар
1
«Все виды тестов используются в наборе инструментов хорошего инженера ПО, и все они имеют сценарии, где они незаменимы». - Хотел бы я проголосовать несколько раз только за это! Люди, которые думают, что они могут просто найти один идеальный инструмент / метод тестирования и применять его повсюду, измотывают меня
ptyx
8

Все виды тестирования очень важны и гарантируют, что различные аспекты системы соответствуют спецификациям. Так что работать задом наперед: «Если бы мне пришлось выбирать один тип тестирования ...», я бы не стал. Модульное тестирование дает мне обратную связь, чем интеграционное тестирование или интерактивное тестирование человеком.

Вот тип / преимущество тестирования, которое мы проводим:

  • Юнит-тестирование - гарантирует, что юниты выполняют работу так, как мы ожидаем. Мы проверяем контракты как с поставщиками, так и с потребителями для каждого интерфейса - и это довольно легко автоматизировать. Мы также проверяем наши граничные условия и т. Д.
  • Интеграционное тестирование - обеспечивает совместную работу подразделений. Это в основном для проверки нашего дизайна. Если что-то здесь сломается, мы должны настроить наши модульные тесты, чтобы убедиться, что это больше не повторится.
  • Тестирование системы - обеспечивает соответствие системы требованиям / спецификациям. Обычно люди делают этот тип тестирования.
  • Приемочное тестирование - клиент делает это, чтобы убедиться, что конечный продукт делает то, что рекламируется.

Необязательное, но рекомендуемое тестирование:

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

Чтобы понять, почему модульное тестирование имеет преимущество перед интеграционным тестированием, вы должны понимать, что дополнительные тесты на порядок должны быть комплексными. Для каждого возможного результата для блока А должен быть тест. То же самое для блока B. Теперь, если оба из них работают вместе для более полного решения, число тестов является комбинаторным. Короче говоря, чтобы проверить каждую перестановку взаимодействия между блоком A и блоком B, вам нужны тесты A * B. Добавьте в единицу C, и количество тестов для трио будет A * B * C.

Именно здесь концепция интерфейсов и границ объектов становится очень важной. Интерфейсы представляют собой определенный контракт. Реализатор интерфейса соглашается , что он будет вести себя определенным образом. Аналогично, потребитель интерфейса соглашается, что он будет использовать реализацию определенным образом. Написав тест, который собирает каждый класс, реализующий интерфейс, вы можете легко проверить, что каждая реализация соблюдает контракты интерфейса. Это половина уравнения. Другая половина - тестирование на стороне потребителя - именно здесь играют роль ложные объекты. Макет настроен на то, чтобы взаимодействия всегда были в спецификации. На данный момент все, что нужно, это несколько интеграционных тестов, чтобы убедиться, что у нас есть правильные контракты между разработчиком и потребителем.

Берин Лорич
источник
«Системное тестирование - обеспечивает соответствие системы требованиям / спецификациям. Обычно люди проводят такой тип тестирования». Системные / функциональные / «сквозные» / высокоуровневые интеграционные тесты также хороши для автоматизации.
MiFreidgeim SO-перестань быть злым
3

Это разные инструменты с разными целями:

  • Модульное тестирование - это инструмент проектирования (TDD) и почти обязательное условие для рефакторинга.

  • Интеграционные тесты хороши для визуализации прогресса проекта, а также для избежания ошибок регрессии.

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

Хавьер
источник
@ Вы не можете по-настоящему проектировать с помощью интеграционных тестов, и вы не найдете регрессий с помощью модульных тестов. В точку!
Chankey Pathak
Модульные тесты могут найти регрессии, вызванные рефакторингом, например, измененный метод общего помощника. Интеграционные тесты гораздо лучше для этого.
StuperUser
Второй пункт об интеграционных тестах включает в себя тесты «система / функционал» (он же «сквозной»)
MiFreidgeim SO-перестать быть злым
Полностью согласен; аналогичное замечание было высказано несколько лет назад Стивом Сандерсоном. См. Таблицу «Цель - Сильнейшая техника» в его сообщении в блоге 2009 года на blog.stevensanderson.com/2009/08/24/…, чтобы узнать о некоторых дополнительных своих соображениях здесь.
Марк А. Фицджеральд
1

Я широко использовал Selenium для проверки работоспособности.

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

Самое замечательное в селене - то, что вы можете связать его с инфраструктурами модульного тестирования, такими как XUnit, TestNG или MSTest.

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

Райан Хейс
источник
1

Лучшая рентабельность инвестиций - это, как правило, самое раннее тестирование, которое может обнаружить этот тип ошибки

Модульное тестирование должно найти большинство ошибок, которые есть только в одном методе или, возможно, в одном компоненте. Он находит ошибки, которые обычно могут быть исправлены за считанные минуты, с общим временем оборота менее одного часа. ОЧЕНЬ дешевые тесты, ОЧЕНЬ дешевые ошибки, чтобы найти и исправить! Если эти ошибки превращают это в интеграционное тестирование, оборот может быть больше похож на день (тестовые прогоны часто происходят ночью), при условии, что ошибка не закрыта другой ошибкой; плюс, вероятно, будет введено больше ошибок, так как другой код был написан против исходного глючного кода; плюс любые изменения будут влиять на большее количество кода. Кроме того, устранение большего количества ошибок означает необходимость выполнения гораздо большего количества тестовых прогонов, прежде чем можно будет завершить интеграционное тестирование. Плохое модульное тестирование часто лежит в основе долгого, обременительного, дорогоготестовые интеграционные циклы. Пропуск модульного тестирования может вдвое сократить время разработки, но тестирование займет по крайней мере в 3-4 раза больше, весь проект удвоится в длине, и у вас все равно будет более низкое качество, чем если бы вы тестировали модуль IME.

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

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

Если бы я собирался автоматизировать только один тип тестирования, это было бы модульное тестирование. Интеграционные тесты могут проводиться вручную и проводились многими крупными компаниями годами. Требуется больше времени, чтобы вручную выполнять работу, которая может выполняться компьютером снова и снова, и гораздо дороже для большинства проектов, не говоря уже о скучной и подверженной ошибкам, но это можно сделать. Пользовательские приемочные тесты часто выполняются вручную, поскольку пользователи часто не знают, как автоматизировать свои тесты, в то же время тестируя то, что их волнует. Модульные тесты ДОЛЖНЫ быть автоматизированы. Вы должны иметь возможность запускать все модульные тесты в течение нескольких секунд по запросу так же часто, как каждые несколько минут. Люди просто не могут даже приблизиться к ручным тестам. Не говоря уже о том, что модульные тесты находятся в коде и не могут быть выполнены без вызова их через код, т. Е. Их автоматизации.

Следует иметь в виду, что это форум в первую очередь для разработчиков, а не для тестировщиков. Интеграционное тестирование в основном осуществляется тестерами. Модульное тестирование осуществляется разработчиками. Естественно, разработчики больше говорят о модульном тестировании, чем другие виды тестирования. Это не значит, что они не думают, что другое тестирование важно. Это просто означает, что они на самом деле этого не делают (или делают это реже).

Этель Эванс
источник
Спасибо за последний абзац, я об этом не думал.
Бьярке Фрейнд-Хансен
К вашему сведению, я обновил ответ, поскольку вы его прочитали - понял, что я недостаточно внимательно прочитал исходный вопрос
Этель Эванс
@EthelEvans, ваши рассуждения о приоритетах модульных тестов верны для новых проектов. Для унаследованных проектов, которые были написаны без учета автоматизации тестирования, наиболее важными являются системные / ака функциональные / ака высокоуровневые интеграционные тесты. Смотрите последнюю часть programmers.stackexchange.com/a/39370/31574 ответа.
MiFreidgeim SO-перестань быть злым
@MichaelFreidgeim, это в конечном итоге зависит от того, насколько стабильны интерфейсы. Автоматизация высокоуровневых тестов может быстро повлечь за собой чрезмерные затраты на обслуживание, если они быстро устаревают. В этом случае автоматизируйте понижение, чтобы помочь построить стабильность, и используйте предварительное тестирование (возможно, на основе сессий или контрольных списков) для E2E и интеграционных тестов, чтобы избежать затрат на обслуживание автоматизации. Однако не все унаследованные проекты имеют стабильные интерфейсы - особенно если они подвергаются реорганизации или агрессивной ре-архитектуре.
Этель Эванс
1

Я чувствую, что приемочные испытания - король в этом сценарии.

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

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

Поэтому модульные тесты могут дать очень ложное чувство безопасности.

godelfiend
источник
0

Вопрос не столько в том, что важнее, сколько в том, что можно автоматизировать и быстро запустить.

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

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

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

Дэвид Торнли
источник