В чем разница между интеграционными и модульными тестами?

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

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

По сути, эти тесты стали интеграционными, потому что теперь они тестируют интеграцию этих двух классов, или это просто unit тест, охватывающий два класса?

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

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

Ответ 1

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

Напротив, unit тест Unit test, тестирующий один метод, основан на (часто ошибочном) допущении, что остальная часть программного обеспечения работает правильно, потому что оно явно имитирует каждую зависимость.

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

Скажем, у вас есть метод где-то вроде этого:

public SomeResults DoSomething(someInput) {
  var someResult = [Do your job with someInput];
  Log.TrackTheFactYouDidYourJob();
  return someResults;
}

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

Feature: To be able to do something
  In order to do something
  As someone
  I want the system to do this thing

Scenario: A sample one
  Given this situation
  When I do something
  Then what I get is what I was expecting for

Нет сомнений: если тест пройден, вы можете утверждать, что поставляете работающую функцию. Это то, что вы можете назвать Бизнес-ценность.

Если вы хотите написать unit тест для DoSomething, вы должны сделать вид (используя некоторые макеты), что остальные классы и методы работают (то есть, что все зависимости, которые использует метод, работают правильно) и утвердить свой метод работает.

На практике вы делаете что-то вроде:

public SomeResults DoSomething(someInput) {
  var someResult = [Do your job with someInput];
  FakeAlwaysWorkingLog.TrackTheFactYouDidYourJob(); // Using a mock Log
  return someResults;
}

Вы можете сделать это с помощью Dependency Injection, с помощью некоторого Factory Method или любой Mock Framework или просто путем расширения тестируемого класса.

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

Функция не будет работать, потому что Log не работает, а не потому, что [Do your job with someInput] не выполняет свою работу. И, кстати, [Do your job with someInput] является единственной ответственностью за этот метод.

Также предположим, что Log используется в 100 других функциях, в 100 других методах 100 других классов.

Да, 100 функций не удастся. Но, к счастью, 100 сквозных тестов также дают сбой и выявляют проблему. И да: они говорят правду.

Это очень полезная информация: я знаю, что у меня сломан продукт. Это также очень запутанная информация: она ничего не говорит мне о том, где проблема. Он сообщает мне симптом, а не основную причину.

Тем не менее, unit тест DoSomething зеленый, потому что он использует фальшивый Log, построенный так, чтобы никогда не ломаться. И да: это явно вранье. Это сообщение сломанной функции работает. Чем это может быть полезно?

(Если unit тест DoSomething() не пройден, убедитесь, что в [Do your job with someInput] есть некоторые ошибки.)

Предположим, что это система со сломанным классом: A system with a broken class

Одна ошибка нарушит несколько функций, а несколько интеграционных тестов не пройдут.

A single bug will break several features, and several integration tests will fail

С другой стороны, та же самая ошибка будет нарушать только один unit тест.

The same bug will break just one unit test

Теперь сравните два сценария.

Та же самая ошибка сломает только один unit тест.

  • Все ваши функции, использующие неработающий Log, красного цвета
  • Все ваши юнит-тесты зеленые, только юнит-тест для Log красный

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

Разница

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

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

Вот почему я думаю, что ваше предложение "Или это просто юнит-тест, охватывающий 2 класса" как-то смещено. Unit тест никогда не должен охватывать 2 класса.

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

Ответ 2

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

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

Ответ 3

Мои 10 бит: D

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

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

Это реальная подвижная линия, хотя я бы предпочел больше сосредоточиться на том, чтобы получить проклятый код для полной остановки ^ _ ^

Ответ 4

В модульных тестах используются макеты

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

Ответ 5

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

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

Технически вы все равно не можете unit test просто один класс. Что делать, если ваш класс состоит из нескольких других классов? Это автоматически делает это интеграционным тестом? Я так не думаю.

Ответ 6

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

В тесте утки (выглядит, шарлатаны, waddles, его утка), его просто unit test с более чем 1 новым объектом в нем.

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

Ответ 7

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

Тестирование интеграции: Тестирование связанных модулей вместе для совместной работы.

Ответ 8

Характер ваших тестов

unit тест модуля X - это тест, который ожидает (и проверяет) проблемы только в модуле X.

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

Подумайте о характере ваших тестов в следующих терминах:

  • Снижение риска: для этого и нужны тесты. Только комбинация модульных тестов и интеграционных тестов может дать вам полное снижение риска, потому что, с одной стороны, модульные тесты по своей сути не могут проверить правильное взаимодействие между модулями, а с другой стороны, интеграционные тесты могут выполнять функции только нетривиального модуля в небольшой степени.
  • Написание тестов: Интеграционные тесты могут сэкономить усилия, так как вам может не понадобиться писать заглушки/подделки/макеты. Но модульные тесты также могут сэкономить усилия, если реализовать (и поддерживать!) Эти заглушки/подделки /mocks оказывается проще, чем конфигурировать настройку теста без них.
  • Задержка выполнения теста: Интеграционные тесты, включающие тяжелые операции (такие как доступ к внешним системам, таким как БД или удаленные серверы), имеют тенденцию быть медленными (er). Это означает, что модульные тесты могут выполняться гораздо чаще, что сокращает усилия по отладке в случае неудачи, потому что вы лучше представляете, что вы изменили за это время. Это становится особенно важным, если вы используете разработку через тестирование (TDD).
  • Усилия по отладке: Если интеграционный тест не пройден, но ни один из модульных тестов не прошел, это может быть очень неудобно, поскольку в нем содержится так много кода, который может содержать проблему. Это не большая проблема, если вы ранее изменили только несколько строк, но поскольку интеграционные тесты выполняются медленно, возможно, вы не запускали их в такие короткие промежутки времени...

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

Прагматичный подход к использованию обоих

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

Ответ 9

На мой взгляд, ответ: "Почему это имеет значение?"

Это потому, что модульные тесты - это то, что вы делаете, а тесты интеграции - это то, чего вы не делаете? Или наоборот? Конечно, нет, вы должны попробовать сделать то и другое.

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

Это потому, что вы используете mocks в модульных тестах, но не используете их в тестах интеграции? Конечно нет. Это означало бы, что если у меня есть полезный интеграционный тест, мне не разрешено добавлять макет для какой-то части, боюсь, мне пришлось бы переименовать мой тест на "unit test" или передать его другому программисту, над которым нужно работать.

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

Это не имеет значения.

Тестирование важно, важно F.I.R.S.T, расщепление волос на определениях - пустая трата времени, которая только путает новичков с тестированием.

Ответ 10

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

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

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

Ответ 11

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

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

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

Ответ 12

Unit Testing - это метод тестирования, который проверяет правильность работы отдельных блоков исходного кода.

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

Wikipedia определяет единицу как самую маленькую тестируемую часть приложения, которая в Java/С# является методом. Но в вашем примере класса Word и Sentence я бы, вероятно, просто написал тесты для предложения, так как я, скорее всего, нахожу, что он перехитрил, чтобы использовать mock класс слова, чтобы проверить класс предложения. Таким образом, предложение будет моим подразделением, а слово - деталью реализации этой единицы.

Ответ 13

Тестирование интеграции: проверяется устойчивость базы данных.
Модульные тесты: доступ к базе данных издевается. Методы кода проверены.

Ответ 14

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

Тестирование интеграции относится к тесту, который выполняется, предпочтительно на сервере интеграции, когда разработчик передает свой код в репозиторий управления версиями. Интеграционное тестирование может выполняться такими утилитами, как Cruise Control.

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

Ответ 15

Я вызываю unit, тестирует те тесты, которые white box проверяет класс. Любые зависимости, требуемые классом, заменяются поддельными (mocks).

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

Я бы не назвал тесты интеграции Controller, если одна из их зависимостей не является реальной (т.е. не подделана) (например, IFormsAuthentication).

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

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

Ответ 16

Простое объяснение с аналогиями

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

Интеграционные тесты

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

Все, что он говорит вам, это то, работает ли общая часть. Если это не удается: он не говорит вам точно, где это происходит.

Модульные тесты

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

Пример: Давайте уточним этот момент на примере:

  • Давайте возьмем автомобиль в качестве примера.
  • Интеграционный тест для автомобиля: например, машина едет в Woop Woop и обратно? Если это произойдет, вы можете с уверенностью сказать, что автомобиль работает с общей точки зрения. Это интеграционный тест. Если он выходит из строя, вы не представляете, где он действительно выходит из строя: это радиатор, трансмиссия, двигатель или карбюратор? У тебя нет идей. Это может быть что угодно.
  • Юнит-тест для автомобиля: работает ли двигатель? Это тестирование предполагает, что все остальное в машине работает просто отлично. Таким образом, если этот конкретный unit тест не пройден: вы можете быть уверены, что проблема заключается в двигателе, поэтому вы можете быстро изолировать и устранить проблему.

Использование заглушек

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

  • Теперь давайте предположим, что в вашем двигателе используется специальная система впрыска топлива и что этот тест двигателя также не удался. Другими словами, как тест на интеграцию, так и тест двигателя не прошли. Где тогда проблема? (Дайте себе 10 секунд, чтобы получить ответ.)

  • Проблема с двигателем или системой впрыска топлива?

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

Ответ 17

Немного академический этот вопрос, не так ли?;-) Моя точка зрения: Для меня интеграционный тест - это тест всей части, а не если две части из десяти собираются вместе. Наш интеграционный тест показывает, будет ли успешная работа мастера (содержащая 40 проектов). Для проектов у нас есть тонны модульных тестов. Самое главное, что касается модульных тестов для меня, заключается в том, что один unit test не должен зависеть от другого unit test. Поэтому для меня оба теста, которые вы описываете выше, являются модульными тестами, если они независимы. Для интеграционных тестов это не должно быть важно.

Ответ 18

Испытывают ли эти тесты интеграционные тесты, потому что теперь они тестируют интеграцию этих двух классов? Или это просто unit test, который охватывает 2 класса?

Думаю, да и да. Ваш unit test, который охватывает 2 класса, стал тестом интеграции.

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

Пример реальной разницы может быть следующим: 1) Массив из 1 000 000 элементов легко тестируется и работает отлично. 2) BubbleSort легко тестируется на макет массива из 10 элементов, а также отлично работает 3) Тестирование интеграции показывает, что что-то не так хорошо.

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

Ответ 19

Кроме того, важно помнить, что как модульные тесты, так и интеграционные тесты могут быть автоматизированы и написаны с использованием, например, JUnit. В тестах интеграции JUnit можно использовать класс org.junit.Assume для проверки доступности элементов среды (например, подключения к базе данных) или других условий.

Ответ 20

В модульном тестировании вы тестируете каждую изолированную часть: enter image description here

В тесте интеграции вы тестируете множество модулей вашей системы:

enter image description here

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

enter image description here

Источники: source1 source2

Ответ 21

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

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