В чем разница между интеграционными и модульными тестами?
Я знаю так называемое определение учебников для модульных тестов и тестов интеграции. Мне интересно, когда пришло время писать модульные тесты … Я напишу их, чтобы охватить как можно больше наборов classов.
Например, если у меня есть class Word
, я напишу некоторые модульные тесты для classа Word
. Затем я начинаю писать свой class Sentence
, и когда ему нужно взаимодействовать со Word
, я часто буду писать свои модульные тесты, чтобы они тестировали как Sentence
и Word
… по крайней мере, в тех местах, где они взаимодействуют.
Испытывают ли эти тесты интеграционные тесты, потому что теперь они тестируют интеграцию этих двух classов или это всего лишь единичный тест, охватывающий 2 classа?
- Что такое Mocking?
- F # разработка и модульное тестирование?
- Макетные функции в Go
- Единичное тестирование Каталог анти-шаблонов
- Как сделать TDD и модульное тестирование в PowerShell?
В общем, из-за этой неопределенной строки я редко буду писать тесты интеграции … или я использую готовый продукт, чтобы убедиться, что все части правильно работают с фактическими интеграционными тестами, хотя они являются ручными и редко повторяются за пределами возможностей каждой индивидуальной функции?
Я недопонимаю интеграционные тесты, или действительно ли очень мало различий между интеграционными и модульными тестами?
редактировать
Спасибо всем за ответы! Я думаю, что из разнообразных ответов ясно, что линия между блоками и интеграционными тестами определенно размыта, и, возможно, это немного педантично, чтобы попытаться выяснить, какие из них и истинный фокус должны оставаться на коде (спасибо @Rob Cooper ). Кроме того, извините, но я не собираюсь принимать никакого ответа, потому что слишком много слишком хороши, и это действительно кажется весьма субъективным.
- В чем разница между модульными тестами и интеграционными тестами?
- Случайные данные в модульных тестах?
- Как я могу тестировать графический интерфейс?
- Следует ли тестировать внутреннюю реализацию или тестировать общественное поведение?
- Какова цель ложных объектов?
- Как использовать MSTest без Visual Studio?
- Неужели плохая практика имеет более одного утверждения в единичном тесте?
Ключевое различие, по моему мнению, в том, что интеграционные тесты показывают, работает ли функция или она нарушена, поскольку они подчеркивают код в сценарии, близком к реальности. Они вызывают один или несколько программных методов или функций и проверяют, действуют ли они так, как ожидалось.
Напротив, тестирование модуля на один метод основывается на предположении (часто ошибочном), что остальная часть программного обеспечения работает правильно, потому что он явно издевается над каждой зависимостью.
Следовательно, когда единичный тест для метода, реализующего какую-либо функцию, является зеленым, это не означает, что функция работает.
Скажем, у вас есть метод где-то вроде этого:
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
Без сомнения: если тест пройдет, вы можете утверждать, что вы выполняете рабочую функцию. Это то, что вы можете назвать Business Value .
Если вы хотите написать модульный тест для DoSomething
вы должны притворяться (используя некоторые из них), что остальные classы и методы работают (то есть: все зависимости, используемые этим методом, правильно работают) и утверждают, что ваш метод работает ,
На практике вы делаете что-то вроде:
public SomeResults DoSomething(someInput) { var someResult = [Do your job with someInput]; FakeAlwaysWorkingLog.TrackTheFactYouDidYourJob(); // Using a mock Log return someResults; }
Вы можете сделать это с помощью Injection Dependency, или с помощью Factory Method или любой Mock Framework или просто расширить тестируемый class.
Предположим, что в Log.DoSomething()
есть ошибка. К счастью, спецификация Gherkin найдет ее, и ваши сквозные тесты не удастся.
Функция не будет работать, потому что Log
нарушен, а не потому, что [Do your job with someInput]
не выполняет свою работу. И, кстати, ответственность за этот метод лежит на [Do your job with someInput]
.
Кроме того, предположим, что Log
используется в 100 других функциях, в 100 других методах из 100 других classов.
Да, 100 функций не удастся. Но, к счастью, 100 сквозных тестов также терпят неудачу и выявляют проблему. И, да: они говорят правду .
Это очень полезная информация: я знаю, что у меня сломанный продукт. Это также очень запутанная информация: она ничего не говорит о том, где проблема. Он сообщает мне симптом, а не первопричину.
Тем не менее, блок-тест DoSomething
является зеленым, потому что он использует поддельный Log
, построенный так, чтобы никогда не ломаться. И да: это явно лжет . Это сообщение об сломанной функции работает. Как это может быть полезно?
(Если не удалось выполнить единичный тест DoSomething()
, убедитесь, что: [Do your job with someInput]
есть некоторые ошибки.)
Предположим, что это система со сломанным classом:
Одна ошибка приведет к разрыву нескольких функций, и несколько интеграционных тестов не удастся.
С другой стороны, одна и та же ошибка сломает только один единичный тест.
Теперь сравните два сценария.
Такая же ошибка сломает только один единичный тест.
- Все ваши функции с использованием разбитого
Log
красные - Все ваши модульные тесты являются зелеными, только проверка устройства для
Log
красная
На самом деле, модульные тесты для всех модhive с использованием сломанной функции являются зелеными, потому что, используя макеты, они удаляют зависимости. Другими словами, они работают в идеальном, полностью вымышленном мире. И это единственный способ изолировать ошибки и искать их. Единичное тестирование означает насмешливость. Если вы не издеваетесь, вы не являетесь модульным тестированием.
Разница
Тесты интеграции показывают, что не работает. Но они бесполезны в угадывании проблемы.
Единичные тесты – это единственные тесты, которые говорят вам, где именно ошибка. Чтобы нарисовать эту информацию, они должны запустить метод в издеваемую среду, где все другие зависимости должны корректно работать.
Вот почему я думаю, что ваше предложение «Или это всего лишь единичный тест, охватывающий 2 classа», каким-то образом смещается. Единичный тест никогда не должен охватывать 2 classа.
Этот ответ в основном представляет собой резюме того, что я написал здесь: единичные тесты лежат, поэтому я их люблю .
Когда я пишу модульные тесты, я ограничиваю объем проверяемого кода classом, который я сейчас пишу, насмешливыми зависимостями. Если я пишу class Sentence, а Sentence имеет зависимость от Word, я буду использовать макет Word. Издеваясь над Word, я могу сосредоточиться только на его интерфейсе и проверять различные типы поведения моего classа Sentence, поскольку он взаимодействует с интерфейсом Word. Таким образом, я только проверяю поведение и реализацию предложения, а не тестирую тестирование Word.
После того, как я написал модульные тесты, чтобы гарантировать, что Sentence ведет себя правильно, когда он взаимодействует с Word на основе интерфейса Word, я пишу интеграционный тест, чтобы убедиться, что мои предположения о взаимодействиях верны. Для этого я поставляю фактические объекты и пишу тест, в котором используется функция, которая в конечном итоге будет использоваться как в Sentence, так и в Word.
Мои 10 бит: D
Мне всегда говорили, что Unit Tests – это тестирование отдельного компонента, который должен выполняться в полном объеме. Теперь это имеет тенденцию иметь много уровней, поскольку большинство компонентов сделаны из меньших частей. Для меня единица является функциональной частью системы. Поэтому он должен обеспечить что-то ценное (т. Е. Не метод для синтаксического анализа строк, но, возможно, HtmlSanitizer ).
Интеграционные тесты – это следующий шаг вверх, его принятие одного или нескольких компонентов и обеспечение их совместной работы, как и следовало бы. Вы находитесь за пределами тонкостей беспокойства о том, как компоненты работают индивидуально, но когда вы вводите html в свой HtmlEditControl , это как-то волшебным образом знает, насколько он действителен или нет.
Это реальная подвижная линия, хотя я бы предпочел больше сосредоточиться на том, чтобы получить проклятый код для полной остановки ^ _ ^
Единичные тесты используют mocks
То, о чем вы говорите, – это интеграционные тесты, которые фактически проверяют всю интеграцию вашей системы. Но когда вы проводите модульное тестирование, вы должны проверить каждый блок отдельно. Все остальное должно насмехаться. Итак, в вашем случае classа Sentence
, если он использует class Word
, тогда ваш class Word
должен быть посмеян. Таким образом, вы будете проверять только функциональность classа Sentence
.
Я думаю, что когда вы начинаете думать об интеграционных тестах, вы говорите больше о пересечении физических слоев, а не о логических слоях.
Например, если ваши тесты касаются генерации контента, это единичный тест: если ваш тест касается только записи на диск, он по-прежнему является модульным тестом, но как только вы проверяете как ввод-вывод, так и содержимое файла, то у вас есть тест интеграции. Когда вы проверяете вывод функции внутри службы, это единичный тест, но после того, как вы выполните служебный вызов и посмотрите, является ли результат функции одинаковым, тогда это интеграционный тест.
Технически вы все равно не можете тестировать один class. Что делать, если ваш class состоит из нескольких других classов? Это автоматически делает это интеграционным тестом? Я так не думаю.
Тестирование устройства: тестирование, проведенное с устройством или с помощью небольшого программного обеспечения. Выполнено, чтобы проверить, удовлетворяет ли оно своей функциональной спецификации или ее предполагаемой структуре дизайна.
Тестирование интеграции. Тестирование связанных модhive вместе для его комбинированных функций.
используя единую конструкцию ответственности, ее черно-белую. Более 1 ответственности, ее интеграционный тест.
По тестированию утки (выглядит, шарлатанцы, waddles, его утка), это всего лишь единичный тест с более чем 1 новым объектом в нем.
Когда вы попадаете в mvc и тестируете его, тесты controllerа всегда являются интеграцией, потому что controller содержит как модель, так и блок просмотра. Логика тестирования в этой модели я бы назвал модульным тестом.
На мой взгляд, ответ: «Почему это важно?»
Это потому, что модульные тесты – это то, что вы делаете, а тесты интеграции – это то, чего вы не делаете? Или наоборот? Конечно, нет, вы должны попытаться сделать то и другое.
Это потому, что модульные тесты должны быть быстрыми, изолированными, повторяемыми, самонастраивающимися и своевременными, а интеграционные тесты не должны? Конечно, нет, все тесты должны быть такими.
Это потому, что вы используете mocks в модульных тестах, но не используете их в тестах интеграции? Конечно нет. Это будет означать, что если у меня есть полезный интеграционный тест, мне не разрешено добавлять макет для какой-то части, боюсь, мне пришлось бы переименовать мой тест на «модульный тест» или передать его другому программисту для работы.
Это из-за того, что модульные тесты проверяют один блок и тесты интеграции тестируют несколько единиц? Конечно нет. Насколько это важно? Теоретическое обсуждение объема тестов на практике все равно разрушается, поскольку термин «единица» полностью зависит от контекста. На уровне classа единица может быть методом. На уровне сборки единица может быть classом, а на уровне обслуживания единица может быть компонентом. И даже classы используют другие classы, так что это единица?
Это не имеет значения.
Тестирование важно, FIRST важен, расщепление волос на определениях – пустая трата времени, которая только путает новичков с тестированием.
Подумайте о характере ваших тестов в следующих терминах:
- Снижение риска : для этого нужны тесты. Только комбинация единичных тестов и интеграционных тестов может дать вам полное снижение риска, потому что модульные тесты могут по своей сути не проверять правильное взаимодействие между модулями и интеграционными тестами, которые могут выполнять функциональность нетривиального модуля только в небольшой степени.
- Тестовое написание : интеграционные тесты могут сэкономить, потому что вам не нужно писать окурки / подделки / издевки. Но модульные тесты также могут сэкономить усилия при реализации (и поддержании!) Этих заглушек / подделок / макетов, которые проще, чем настройка тестовой установки без них.
- Задержка выполнения теста . Интеграционные тесты, включающие тяжеловесные операции (например, доступ к внешним системам, таким как БД или удаленные серверы), как правило, медленные. Это означает, что модульные тесты могут выполняться гораздо чаще, что снижает эффективность отладки, если что-то не удается, потому что вы лучше понимаете, что вы изменили за это время. Это становится особенно важным, если вы используете тестовую разработку (TDD).
- Устранение отладки : если тесты интеграции не сработают, но ни один из модульных тестов не делает этого, это может быть очень неудобно, потому что существует очень много кода, который может содержать проблему. Это не большая проблема, если вы ранее меняли только несколько строк, но поскольку тесты интеграции выполняются медленно, вы, возможно, не запускали их за такие короткие промежутки времени …
Помните, что интеграционный тест может все еще заглушить / подделать / высмеять некоторые из его зависимостей. Это обеспечивает множество промежуточных результатов между модульными тестами и системными тестами (самые всесторонние интеграционные тесты, тестирование всей системы).
Таким образом, прагматичный подход: гибко полагаться на интеграционные тесты, насколько вы разумно можете, и использовать модульные тесты, где это было бы слишком рискованно или неудобно. Такой способ мышления может быть более полезным, чем некоторая догматическая дискриминация модульных тестов и интеграционных тестов.
Я думаю, что по-прежнему я бы назвал пару взаимодействующих classов единичным тестом при условии, что модульные тесты для classа 1 проверяют функции classа1, а модульные тесты для classа 2 проверяют его функции, а также что они не попадают в базу данных.
Я называю тест интеграционным тестом, когда он проходит через большую часть моего стека и даже попадает в базу данных.
Мне очень нравится этот вопрос, потому что обсуждение TDD иногда кажется мне слишком пуристским, и мне хорошо видеть некоторые конкретные примеры.
Я делаю то же самое – я называю их всеми модульными тестами, но в какой-то момент у меня есть «единичный тест», который охватывает так много, что я часто переименовываю его в «..IntegrationTest» – только изменение имени, ничего не меняется.
Я думаю, что существует продолжение от «атомных тестов» (тестирование одного крошечного classа или метода) на модульные тесты (class) и интеграционные тесты, а затем функциональный тест (который обычно покрывает намного больше материалов сверху вниз) – там, кажется, нет чистого отсечения.
Если ваш тест устанавливает данные и, возможно, загружает базу данных / файл и т. Д., То, возможно, это больше интеграционный тест (интеграционные тесты, которые я нахожу, используют меньше макетов и более реальных classов, но это не значит, что вы не можете издеваться над некоторыми системы).
Unit Testing – это метод тестирования, который проверяет правильность работы отдельных блоков исходного кода.
Интеграция Тестирование – это этап тестирования программного обеспечения, в котором отдельные программные модули объединяются и тестируются как группа.
Википедия определяет единицу как самую маленькую тестируемую часть приложения, которая в Java / C # является методом. Но в вашем примере classа Word и Sentence я, вероятно, просто напишу тесты для предложения, так как я, скорее всего, найду его излишним, чтобы использовать class макетного слова, чтобы проверить class предложения. Таким образом, предложение будет моим подразделением, а слово – деталью реализации этой единицы.
Тесты интеграции: проверяется постоянство базы данных.
Модульные тесты: доступ к базе данных издевается. Методы кода проверены.
Тестирование модhive тестируется на единицу работы или блок кода, если хотите. Обычно выполняется одним разработчиком.
Тестирование интеграции относится к тесту, который выполняется, предпочтительно на сервере интеграции, когда разработчик передает свой код в repository управления версиями. Тестирование интеграции может выполняться такими утилитами, как Cruise Control.
Таким образом, вы выполняете модульное тестирование, чтобы проверить, что рабочая единица, которую вы создали, работает, а затем интеграционный тест подтверждает, что все, что вы добавили в repository, не сломало что-то еще.
Немного академический этот вопрос, не так ли? 😉 Моя точка зрения: для меня интеграционный тест – это проверка всей части, а не две части из десяти вместе. Наш интеграционный тест показывает, будет ли успешная работа мастера (содержащая 40 проектов). Для проектов у нас есть тонны модульных тестов. Самое важное, что касается модульных тестов для меня, заключается в том, что один единичный тест не должен зависеть от другого модульного теста. Поэтому для меня оба теста, которые вы описываете выше, являются модульными тестами, если они независимы. Для интеграционных тестов это не обязательно важно.
Я называю unit-тестирование этих тестов, которые white box тестируют class. Любые зависимости, требуемые classом, заменяются поддельными (mocks).
Интеграционные тесты – это те тесты, в которых одновременно тестируются несколько classов и их взаимодействия. Только некоторые зависимости в этих случаях подделываются / издеваются.
Я бы не назвал интеграционные тесты Controller, если одна из их зависимостей не является реальной (т. Е. Не подделана) (например, IFormsAuthentication).
Разделение двух типов тестов полезно для тестирования системы на разных уровнях. Кроме того, интеграционные тесты, как правило, долговечны, и модульные тесты должны быть быстрыми. Различие в скорости выполнения означает, что они выполняются по-разному. В наших процессах dev модульные тесты запускаются при регистрации (что прекрасно, потому что они супер быстрые), а тесты интеграции выполняются один раз / два раза в день. Я стараюсь как можно чаще запускать интеграционные тесты, но, как правило, попадаю в базу данных / записываю файлы / заставляя замедлить работу / etc / rpc.
Это поднимает еще один важный момент, модульные тесты должны избегать удара IO (например, диска, сети, db). В противном случае они замедляются. Требуется немного усилий для разработки этих зависимостей ввода-вывода – я не могу признать, что я верен правилу «единичные тесты должны быть быстрыми», но, если вы, преимущества в гораздо более крупной системе становятся очевидными очень быстро ,
Вышеприведенные примеры очень хорошо, и мне не нужно их повторять. Поэтому я сосредоточусь на использовании примеров, которые помогут вам понять.
Интеграционные тесты
Интеграционные тесты проверяют, все ли работает вместе. Представьте себе серию винтиков, работающих вместе в часах. Интеграционным тестом было бы: часы показывают правильное время? Он все еще говорит о правильном времени через 3 дня?
Все это говорит о том, работает ли общий кусок. Если он терпит неудачу: он не сообщает вам, где именно он терпит неудачу.
Тесты модhive
Это действительно конкретные типы тестов. Они говорят вам, работает ли какая-то конкретная вещь или нет. Ключом к этому типу теста является то, что он проверяет только одну конкретную вещь, предполагая, что все остальное работает нормально. Это ключевой момент.
Пример. Давайте рассмотрим этот пример, используя пример:
- Давайте возьмем автомобиль в качестве примера.
- Тест на интеграцию автомобиля: например, автомобильные приводы в Эчука и обратно. Если это так, вы можете с уверенностью сказать, что автомобиль работает с общей точки обзора. Это интеграционный тест. Если это не удается, вы понятия не имеете, где это происходит: это радиатор, трансмиссия, двигатель или карбюратор? Ты понятия не имеешь. Это может быть что угодно.
- Единичный тест для автомобиля: что двигатель работает. Эти тесты предполагают, что все остальное в машине работает нормально. Таким образом, если этот конкретный модульный тест терпит неудачу: вы можете быть очень уверены в том, что проблема заключается в движке, поэтому вы можете быстро изолировать и устранить проблему.
Последствия смешивания ваших интеграционных и модульных тестов:
-
Предположим, что ваш тест интеграции с автомобилем не прошел. Он не успешно ездит к Эчуке. В чем проблема?
-
Вы смотрите в своем тесте на двигатель. Но в этом конкретном случае в тесте двигателя используются внешние зависимости: в нем используется специальная топливная система. Предположим, что испытание на модуле двигателя также потерпело неудачу. Другими словами, как тест интеграции, так и тест блока двигателя не удались. Где же тогда проблема? (Дайте себе 10 секунд, чтобы получить ответ.) • Не сработал ли двигатель, или это была топливная система, из-за которой двигатель вышел из строя?
Вы видите проблему здесь? Вы не знаете, что именно терпит неудачу. Если вы используете 10 зависимостей, то каждый из этих 10 может вызвать проблему – и вы не будете знать, с чего начать. Вот почему модульные тесты насмехаются над тем, что все остальное работает нормально.
Надеюсь, это поможет.
Испытывают ли эти тесты интеграционные тесты, потому что теперь они тестируют интеграцию этих двух classов? Или это всего лишь единичный тест, который охватывает 2 classа?
Я думаю, Да и Да. Тестирование подразделения, которое охватывает 2 classа, стало интеграционным тестом.
Вы можете избежать этого путем тестирования classа Sentence с макетной реализацией – classа MockWord, что важно, когда эти части системы достаточно велики, чтобы быть реализованы различными разработчиками. В этом случае Word тестируется отдельно, Sentence тестируется с помощью MockWord, а затем Sentence тестируется на интеграцию с Word.
Экзамен реальных различий может быть следующим: 1) Массив из 1 000 000 элементов легко тестируется на единицу и отлично работает. 2) BubbleSort легко тестируется на модуле из 10 элементов, а также отлично работает 3) Интеграционное тестирование показывает, что что-то не так хорошо.
Если эти части разрабатываются одним человеком, наиболее вероятная проблема будет обнаружена при модульном тестировании BubbleSoft только потому, что у разработчика уже есть реальный массив, и он не нуждается в макетной реализации.
Кроме того, важно помнить, что как модульные тесты, так и интеграционные тесты могут быть автоматизированы и написаны с использованием, например, JUnit. В тестах интеграции JUnit можно использовать class org.junit.Assume
для проверки доступности элементов среды (например, подключения к базе данных) или других условий.