В чем разница между макетом и заглушкой?

963

Я читал различные статьи о насмешках против окурков в тестировании, в том числе «Мокки Мартина Фаулера» - не заглушки , но до сих пор не понимаю разницу.

never_had_a_name
источник
75
@OP Потому что нет никакой разницы. Эта статья, столь любимая сообществом, - при всем уважении - делает все ненужное запутанным, добавляя дополнительный смысл к словам, которые легко понять иначе, и делая ненужные вещи сложными. Мок - это всего лишь мошенничество, то, что вместо реальной использует ложную бизнес-логику. Проверка на поведение в конце концов - ваш выбор, но это все еще насмешка. Или как хотите, но называйте это ОДИН. Не разбивайте волосы. Сохраняйте это простым, чтобы люди могли легко понять вашу концепцию - с какой из вышеприведенных статей ничего не получится.
WST
10
«Классификация между издевательствами, подделками и окурками крайне противоречива в литературе». Со многими цитатами. Еще одна из моих любимых цитат из Википедии - если такая вещь существует :) en.wikipedia.org/wiki/Mock_object
JD.
11
что статью Мартина Фаулера действительно трудно понять новичкам.
lmiguelvargasf
1
Насколько я понимаю, заглушка будет просто выброшенным объектом для вашего теста, например, набором фиктивных данных. Mock - это искусно переопределенная версия чего-то более сложного, например, сервисный уровень с различными методами, которые вы могли бы изменить в своих тестах. Две вещи используются вместе, как вы могли бы передать некоторые заглушенные объекты в ваш смоделированный слой.
JsonStatham

Ответы:

746

огрызок

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

издеваться

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

Разница между издевательствами и окурками

Тесты, написанные с помощью макетов, обычно следуют initialize -> set expectations -> exercise -> verifyшаблону тестирования. В то время как предварительно написанная заглушка будет следовать за initialize -> exercise -> verify.

Сходство между издевательствами и окурками

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

Шон Копенхейвер
источник
876

предисловие

Есть несколько определений объектов, которые не являются реальными. Общий термин - тестовый двойной . Этот термин включает в себя: манекен , подделка , заглушка , макет .

Ссылка

Согласно статье Мартина Фаулера :

  • фиктивный объекты передаются, но никогда не используются. Обычно они просто используются для заполнения списков параметров.
  • Не настоящие объекты на самом деле имеют рабочие реализации, но обычно используют некоторые ярлыки, которые делают их непригодными для производства (хороший пример - база данных в памяти).
  • Столбики обеспечивают постоянные ответы на вызовы, сделанные во время теста, обычно вообще не реагируя ни на что, кроме того, что запрограммировано для теста. Заглушки могут также записывать информацию о вызовах, такую ​​как заглушка шлюза электронной почты, которая запоминает сообщения, которые она «отправила», или, возможно, только сколько сообщений она «отправила».
  • Мок - это то, о чем мы здесь говорим: объекты, предварительно запрограммированные с ожиданиями, которые формируют спецификацию вызовов, которые они ожидают получить.

Стиль

Mocks vs Stubs = Поведенческое тестирование против государственного тестирования

Принцип

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

Жизненный цикл

Тест жизненного цикла с заглушками:

  1. Настройка - Подготовьте объект, который тестируется, и его заглушки.
  2. Упражнение - Проверьте функциональность.
  3. Проверить состояние - используйте подтверждения для проверки состояния объекта.
  4. Разрушение - Очистить ресурсы.

Тест жизненного цикла с макетами:

  1. Данные настройки - подготовьте объект, который тестируется.
  2. Настройка ожиданий - подготовьте ожидания в макете, который используется основным объектом.
  3. Упражнение - Проверьте функциональность.
  4. Проверьте ожидания - Убедитесь, что в макете были вызваны правильные методы.
  5. Проверить состояние - используйте подтверждения для проверки состояния объекта.
  6. Разрушение - Очистить ресурсы.

Резюме

И тесты на издевательства и окурки дают ответ на вопрос: каков результат?

Тестирование с помощью макетов также интересует: Как был достигнут результат?

Рышард Деган
источник
Подожди, издевается и вернет консервированные ответы? Потому что иначе, почему они отвечают на вопрос?
AturSams
Из того, что вы написали, я могу сказать, что mocks = заглушки + ожидания и проверки, потому что mocks «обеспечивают постоянные ответы на вызовы, сделанные во время теста, обычно вообще не реагируя ни на что, кроме того, что запрограммировано для теста» (так же, как заглушки). И пример, который Фаулер показал в качестве примера заглушки, на самом деле является примером шпиона! Это означает, что макет - это заглушка, а шпион - заглушка. А заглушка - это просто объект, имеющий несколько рабочих методов. Это также объясняет, почему Mockito отказался от метода stub ().
колобок
Что меня смущает в этом, и принятый ответ - это «установка ожидания», что это вообще означает? Обычно в «основном коде» вы создаете ожидаемые результаты. Звучит так, будто вы как-то вводите ожидания в фиктивный объект, что для меня не имеет смысла. ТАКЖЕ, вы также можете легко использовать макет с некоторой информацией, сохранить результат, создать «ожидания» позже и затем сравнить. Вы используете терминологию, которая мне кажется слишком абстрактной и неоднозначной.
IceFire
365

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

Арнис Лапса
источник
33
Я думаю, что это самый краткий и точный ответ. Еда на вынос: фиктивная заглушка IS-A. stackoverflow.com/a/17810004/2288628 - более длинная версия этого ответа.
PoweredByRice
8
Я не думаю, что издевательство - заглушка. Насмешки используются для утверждения и никогда не должны возвращать данные, заглушки используются для возврата данных и никогда не должны утверждать.
dave1010
2
@ dave1010 Mocks определенно может вернуть данные или даже вызвать исключение. Они должны сделать это в ответ на переданные им параметры.
Трентон
2
@trenton если объект возвращает или выбрасывает на основе переданных данных, то это подделка , а не подделка . Заглушки проверяют, как ваша SUT обрабатывает получение сообщений, проверяют, как ваша SUT отправляет сообщения. Смешение 2 может привести к плохому дизайну ОО.
dave1010
8
Я думаю, что это здорово - заглушка возвращает ответы на вопросы. Макет также возвращает ответы на вопросы (это заглушка), но он также подтверждает, что вопрос был задан !!
Лейф
238

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

  • Пустышка - просто фиктивные ценности для удовлетворения API.

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

  • Fake - создать тестовую реализацию класса, которая может зависеть от какой-то внешней инфраструктуры. (Рекомендуется, чтобы ваш модульный тест НЕ взаимодействовал с внешней инфраструктурой.)

    Пример : создание ложной реализации для доступа к базе данных, замена ее на in-memoryколлекцию.

  • Stub - переопределить методы для возврата жестко закодированных значений, также называемых state-based.

    Пример : ваш тестовый класс зависит от метода, который Calculate()занимает 5 минут. Вместо того, чтобы ждать 5 минут, вы можете заменить его реальную реализацию заглушкой, которая возвращает жестко закодированные значения; занимая лишь небольшую долю времени.

  • Макет - очень похоже, Stubно interaction-basedскорее не на основе государства. Это означает, что вы не ожидаете отMock возврата какого-либо значения, а предполагаете, что выполняется определенный порядок вызовов методов.

    Пример: вы тестируете класс регистрации пользователя. После звонка Saveследует позвонить SendConfirmationEmail.

Stubsи Mocksфактически являются подтипами Mock, оба заменяют реальную реализацию тестовой реализацией, но по разным, конкретным причинам.

лев
источник
175

В курсе codeschool.com , Тестирование Rails для Зомби , они дают следующее определение терминов:

огрызок

Для замены метода кодом, который возвращает указанный результат.

издеваться

Заглушка с утверждением, что метод вызывается.

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

Диллон Кернс
источник
В дополнение к посту Диллона, подумайте об этом, у вас есть класс под названием «MakeACake», который берет несколько библиотек: молоко, яйца, сахар, духовка.
aarkerio
139

Заглушки не проваливаются, тестировать можно.

mk_
источник
2
И я думаю, что это хорошо, вы знаете, если тесты имеют такое же поведение после рефакторинга.
RodriKing
1
@RodriKing У меня такое же чувство. Как и в случае с Mock, с любыми изменениями в рабочем коде - у вас есть соответствующие изменения в тестовом коде. Какая боль! С заглушками, вы чувствуете, что вы продолжаете тестировать поведение, поэтому нет необходимости вносить микро изменения в тестовый код.
tucq88
35

Я думаю, что самый простой и ясный ответ на этот вопрос дан Роем ​​Ошеровом в его книге «Искусство модульного тестирования» (стр. 85).

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

С другой стороны, тест будет использовать фиктивный объект, чтобы проверить, провалился ли тест или нет. [...]

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

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

Гини Антонио
источник
2
Я хотел бы, чтобы ваш ответ нашел путь к вершине. Вот Р. Ошеров объясняет это youtu.be/fAb_OnooCsQ?t=1006 .
Майкл Экока
31

Прочитав все объяснения, приведенные выше, я попытаюсь сжать:

  • Stub : фиктивный кусок кода, который позволяет запустить тест, но вам все равно, что с ним происходит.
  • Макет : фиктивный кусок кода, который вы ПРОВЕРЯЕТЕ, правильно вызывается как часть теста.
  • Spy : фиктивный фрагмент кода, который перехватывает некоторые вызовы реального фрагмента кода, позволяя вам проверять вызовы без замены всего исходного объекта.
O'Rooney
источник
4
Хороший ответ. Хотя Mock звучит очень похоже на Spy, основываясь на вашем определении. Было бы неплохо, если бы вы обновили свой ответ, включив в него еще несколько тестовых пар.
Роуэн Гонтьер
Я не слышал о Spy, когда писал этот ответ.
О'Руни
23

Mock - это просто тестирование поведения, проверка того, что определенные методы вызываются. Stub - это тестируемая версия (как таковая) конкретного объекта.

Что вы имеете в виду путь Apple?

NebulaFox
источник
19
"Что ты имеешь в виду под Apple?" Используйте Helvetica
Куби
7
Apple, в отличие от Microsoft :)
never_had_a_name
2
Помогает ли это ситуации?
NebulaFox
21

Если вы сравните это с отладкой:

Stub - это как проверка того, что метод возвращает правильное значение

Mock - это то же самое, что войти в метод и убедиться, что все внутри правильно, прежде чем возвращать правильное значение.

Счастливчик Гилмор
источник
20

Используя ментальную модель действительно помогло мне понять это, а не все объяснения и статьи, которые не совсем «утонули».

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

Теперь, скажем, у вас нет замены пластика, поэтому вы объясняете: «Если вы продолжите играть с ним, он сломается!». Это заглушка , вы заранее указали заранее заданное состояние.

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

Moshisho
источник
19

Я думаю, что самое важное различие между ними - это их намерения.

Позвольте мне попытаться объяснить это в ПОЧЕМУ заглушка против ПОЧЕМУ насмешливый

Предположим, я пишу тестовый код для общедоступного контроллера временной шкалы моего mac-клиента

Вот тестовый образец кода

twitter_api.stub(:public_timeline).and_return(public_timeline_array)
client_ui.should_receive(:insert_timeline_above).with(public_timeline_array)
controller.refresh_public_timeline
  • STUB: Сетевое подключение к Twitter API очень медленное, что делает мой тест медленным. Я знаю, что он вернет временные шкалы, поэтому я сделал заглушку, имитирующую HTTP Twitter API, чтобы мой тест выполнялся очень быстро, и я могу запустить тест даже в автономном режиме.
  • MOCK: Я еще не написал ни один из своих методов пользовательского интерфейса, и я не уверен, какие методы мне нужно написать для моего объекта пользовательского интерфейса. Я надеюсь узнать, как мой контроллер будет взаимодействовать с моим объектом пользовательского интерфейса, написав тестовый код.

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

Я предлагаю прочитать эту статью, если вы пытаетесь узнать больше о макетах: http://jmock.org/oopsla2004.pdf

Джо Ян
источник
1
Я думаю, у вас есть правильная идея, но Диллон Кернс объяснил это намного яснее.
О'Руни
19

Быть очень понятным и практичным:

Заглушка: класс или объект, который реализует методы класса / объекта, которые нужно подделать и всегда возвращает то, что вы хотите.

Пример в JavaScript:

var Stub = {
   method_a: function(param_a, param_b){
      return 'This is an static result';
   }
}

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

Как говорит @mLevan, представьте в качестве примера, что вы тестируете класс регистрации пользователей. После вызова Save, он должен вызвать SendConfirmationEmail.

Очень глупый код Пример:

var Mock = {
   calls: {
      method_a: 0
   }

   method_a: function(param_a, param_b){
     this.method_a++; 
     console.log('Mock.method_a its been called!');
   }
}
R01010010
источник
16

Этот слайд объясняет основные отличия очень хорошо.

введите описание изображения здесь

* Из CSE 403, лекция 16, Вашингтонский университет (слайд, созданный Марти Степпом)

Авирам Файербергер
источник
Это более четкое объяснение различий между ними, ИМО. Для заглушки: тестер берет заглушку и использует ее непосредственно внутри тестируемого класса. Но для Mock тестер должен определить способ использования объекта Mock. В разных случаях он будет вести себя по-разному. Напротив, заглушка не должна вести себя по-разному, но используется как есть (то есть возвращает те же данные, когда с ними связываются)
Декстер
12

Мне нравится объяснение Роя Ошерова [ссылка на видео] .

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

nitishagar
источник
12
  • Стабс против Мокса
    • Столбики
      1. дать конкретные ответы на вызовы методов
        • ex: myStubbedService.getValues ​​() просто возвращает строку, необходимую для тестируемого кода
      2. используется тестируемым кодом для его изоляции
      3. не может пройти тест
        • ex: myStubbedService.getValues ​​() просто возвращает значение заглушки
      4. часто реализуют абстрактные методы
    • Mocks
      1. «суперсет» окурков; Можно утверждать, что определенные методы вызваны
        • ex: убедитесь, что myMockedService.getValues ​​() вызывается только один раз
      2. используется для проверки поведения тестируемого кода
      3. может не пройти тест
        • пример: убедитесь, что myMockedService.getValues ​​() был вызван один раз; проверка не пройдена, потому что myMockedService.getValues ​​() не был вызван моим протестированным кодом
      4. часто издевается над интерфейсами
Relu Mesaros
источник
11

давайте посмотрим тест двойников:

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

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

Алиреза Рахмани Халили
источник
1
лучший ответ на мой взгляд
Эро Стефано
9

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

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

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

Что означает тестовый прогон?
Пример в приведенном ниже коде:

 public void Analyze(string filename)
        {
            if(filename.Length<8)
            {
                try
                {
                    errorService.LogError("long file entered named:" + filename);
                }
                catch (Exception e)
                {
                    mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror");
                }
            }
        }

Вы хотите проверить mailService.SendEMail () , для этого вам нужно смоделировать исключение в вашем тестовом методе, поэтому вам просто нужно создать класс Fake Stub errorService для имитации этого результата, тогда ваш тестовый код сможет протестировать mailService.SendEMail () метод. Как видите, вам нужно смоделировать результат из другого класса External Dependency ErrorService.

Мустафа Экичи
источник
8

Сразу же из статьи Mock Roles, а не Objects , разработчиками jMock:

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

Итак, основные отличия:

  • ожидания, заданные для заглушек, обычно являются общими, в то время как ожидания, заданные для заглушек, могут быть более «умными» (например, вернуть это при первом вызове, это при втором и т. д.).
  • Заглушки в основном используются для настройки косвенных входов SUT , в то время как макеты могут использоваться для проверки как косвенных входов, так и косвенных выходов SUT.

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

Dimos
источник
1
я думаю, что вы правы, но именно поэтому статья Фаулера сбивает с толку, название статьи "Насмешки - это не заглушки" ... но они есть ?! ¯_ (ツ) _ / ¯
stonedauwg
@stonedauwg, действительно, я отредактировал свой пост, чтобы включить ваш каламбур и разъяснения. Надеюсь, это поможет немного больше.
Димос
@stonedauwg, макет - это не заглушка, как прямоугольник, а не квадрат. :)
seanriordan08
7

Я читал «Искусство модульного тестирования» и наткнулся на следующее определение:

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

Афонсо Матос
источник
5

Я наткнулся на эту интересную статью UncleBob The Little Mocker . Это объясняет всю терминологию в очень простой для понимания форме, поэтому она полезна для начинающих. Статья Мартина Фаулерса очень читаема, особенно для таких начинающих, как я.

искусственный интеллект
источник
4

Заглушка помогает нам запустить тест. Как? Это дает значения, которые помогают запустить тест. Эти значения сами по себе не являются реальными, и мы создали эти значения только для запуска теста. Например, мы создаем HashMap, чтобы дать нам значения, которые аналогичны значениям в таблице базы данных. Поэтому вместо непосредственного взаимодействия с базой данных мы взаимодействуем с Hashmap.

Мок это поддельный объект, который запускает тест. где мы утверждаем.

Гарри
источник
«Поэтому вместо непосредственного взаимодействия с базой данных мы взаимодействуем с Hashmap». ... потому что у меня еще не было времени на кодирование модуля базы данных, и мы не могли запустить тестовый код без использования заглушки. Иначе тот же самый Hasmap был бы издевательством! правильно?
Борис Деппен
4

Ниже приведен пример использования mocks против заглушек с использованием C # и Moq framework. В Moq нет специального ключевого слова для Stub, но вы можете использовать объект Mock для создания заглушек.

namespace UnitTestProject2
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    [TestClass]
    public class UnitTest1
    {
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));

            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Once);
        }
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(0);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Never);
        }
        /// <summary>
        /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
        {
            // Arrange 
            var stubEntityRepository = new Mock<IEntityRepository>();
            stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
                .Returns("Stub");
            const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
            var entity = new EntityClass(stubEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
        }
    }
    public class EntityClass
    {
        private IEntityRepository _entityRepository;
        public EntityClass(IEntityRepository entityRepository)
        {
            this._entityRepository = entityRepository;
        }
        public string Name { get; set; }
        public string GetNameWithPrefix(int id)
        {
            string name = string.Empty;
            if (id > 0)
            {
                name = this._entityRepository.GetName(id);
            }
            return "Mr. " + name;
        }
    }
    public interface IEntityRepository
    {
        string GetName(int id);
    }
    public class EntityRepository:IEntityRepository
    {
        public string GetName(int id)
        {
            // Code to connect to DB and get name based on Id
            return "NameFromDb";
        }
    }
}
Адарш Шах
источник
4

Точка зрения Stub и Mock:

  • Stub - это фиктивная реализация, выполненная пользователем в статическом виде, то есть при написании Stub кода реализации. Таким образом, он не может обрабатывать определение сервиса и динамическое состояние. Обычно это делается в платформе JUnit без использования фреймворка.

  • Mock также является фиктивной реализацией, но ее реализация осуществляется динамическим образом с использованием Mocking Frameworks, таких как Mockito. Таким образом, мы можем обрабатывать определение условий и сервисов как динамический путь, т.е. макеты могут создаваться динамически из кода во время выполнения. Таким образом, используя mock, мы можем реализовать Stubs динамически.

Premraj
источник
3

Плюс полезные ответы, одна из самых мощных точек использования Mocks, чем Subs

Если соавтор [от которого зависит основной код] не находится под нашим контролем (например, из сторонней библиотеки),
в этом случае заглушку труднее написать, чем смоделировать .

ahmednabil88
источник
2

Я использовал примеры Python в своем ответе, чтобы проиллюстрировать различия.

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

class Foo(object):
    def bar1(self):
        pass

    def bar2(self):
        #or ...
        raise NotImplementedError

    def bar3(self):
        #or return dummy data
        return "Dummy Data"

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

mymodule.py:

import os
import os.path

def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

test.py:

from mymodule import rm
import mock
import unittest

class RmTestCase(unittest.TestCase):
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os):
        rm("any path")
        # test that rm called os.remove with the right parameters
        mock_os.remove.assert_called_with("any path")

if __name__ == '__main__':
    unittest.main()

Это очень простой пример, который просто запускает rm и подтверждает параметр, с которым он был вызван. Вы можете использовать mock с объектами, а не только с функциями, как показано здесь, и вы также можете возвращать значение, так что фиктивный объект может использоваться для замены заглушки для тестирования.

Еще подробно unittest.mock , заметка в python 2.x mock не включена в unittest, но является загружаемым модулем, который можно загрузить через pip (pip install mock).

Я также прочитал «Искусство модульного тестирования» Роя Ошерова, и я думаю, было бы здорово, если бы подобная книга была написана с использованием примеров на Python и Python. Если кто-нибудь знает о такой книге, пожалуйста, поделитесь. Ура :)

radtek
источник
2

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

simon.denel
источник
2

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

function foo(){}

Макет - это искусственная функция, которая используется во избежание зависимостей ОС, среды или оборудования во время тестов:

function foo(bar){ window = this; return window.toString(bar); }

С точки зрения утверждений и состояния:

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

Ссылки

Пол Суатте
источник
2
+1 за добавление шпионов в глоссарий. Кроме того, я думаю, что вы имеете в виду «Шпионы настроены как шутки», а не «Шпионы настроены как пни»
Самех Дибес
2

Макет - это и технический, и функциональный объект.

Макет технический . Он действительно создается библиотекой-имитатором (EasyMock, JMockit и совсем недавно Mockito известны этим) благодаря генерации байт-кода .
Пробная реализация генерируется в пути , где мы могли бы инструмент его возвращать значение специфического , когда метод вызывается , но и некоторые другие вещи , такие как проверка , что пробный метод был вызван с некоторыми параметрами конкретных (строгая проверка) или каким - либо параметрами ( строгой проверки нет).

Пример издевательства:

@Mock Foo fooMock

Запись поведения:

when(fooMock.hello()).thenReturn("hello you!");

Проверка вызова:

verify(fooMock).hello()

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

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


Заглушка - это просто функциональный объект: это экземпляр класса, который нам нужно изолировать от SUT, и все. Это означает, что и класс-заглушка, и все приспособления поведения, необходимые во время наших модульных тестов, должны быть определены явно.
Например, для заглушки hello()потребуется создать подкласс Fooкласса (или реализовать его интерфейс, который у него есть) и переопределить hello() :

public class HelloStub extends Hello{    
  public String hello { 
      return "hello you!"; 
  }
}

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

public class HelloStub extends Hello{    
  public HelloStub(String helloReturn){
       this.helloReturn = helloReturn;
  }
  public String hello { 
      return helloReturn; 
  }
}

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


Вывод

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


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

davidxxx
источник