Какая разница между фальсификацией, издевательством и укусом?

Я знаю, как я использую эти термины, но мне интересно, были ли принятые определения фальсификации, mocking и stubbing для модульные тесты? Как вы определяете их для своих тестов? Опишите ситуации, в которых вы можете использовать каждый.

Вот как я их использую:

Fake: класс, который реализует интерфейс, но содержит фиксированные данные и никакой логики. Просто возвращает "хорошие" или "плохие" данные в зависимости от реализации.

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

Stub. Как класс mock, за исключением того, что он не дает возможности проверить, что методы были вызваны/не вызваны.

Mocks и заглушки могут быть сгенерированы или сгенерированы с помощью насмешливой структуры. Поддельные классы создаются вручную. Я использую mocks прежде всего для проверки взаимодействия между моим классом и зависимыми классами. Я использую заглушки, когда я проверил взаимодействия и тестирую альтернативные пути через свой код. Я использую поддельные классы, прежде всего, для абстрагирования зависимостей данных или когда mocks/stub слишком утомительны для настройки каждый раз.

Ответ 1

Вы можете получить информацию:

От Мартин Фаулер о Mock и Stub

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

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

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

Из xunitpattern:

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

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

Mock Object, который реализует тот же интерфейс, что и объект, на котором зависит SUT (System Under Test). Мы можем использовать Mock Object в качестве точки наблюдения, когда нам нужно выполнить проверку поведения, чтобы избежать наличия непроверенного требования (см. "Ошибки производства на странице X" ), вызванного неспособностью наблюдать побочные эффекты методов вызова на SUT.

Лично

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

Ответ 2

Stub - объект, предоставляющий предопределенные ответы на вызовы методов.

Mock - объект, на который вы устанавливаете ожидания.

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

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

Ответ 3

Я удивлен, что этот вопрос существует так долго, и никто еще не дал ответ на основе Роя Ошерова "Искусство модульного тестирования".

В "3.1 Введение заглушек" заглушка определяется как:

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

И определяет разницу между заглушками и макетами как:

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

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

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

  • Когда ваш тест проверяет значения в тестируемом классе или где-то еще, кроме подделки, подделка использовалась в качестве заглушки. Он просто предоставлял значения для использования тестируемым классом, либо напрямую через значения, возвращаемые вызовами к нему, либо косвенно, вызывая побочные эффекты (в каком-то состоянии) в результате вызовов к нему.
  • Когда ваш тест проверяет значения подделки, он использовался как макет.

Пример теста, в котором класс FakeX используется в качестве заглушки:

const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);

cut.SquareIt;

Assert.AreEqual(25, cut.SomeProperty);

fake экземпляр используется как заглушка, потому что Assert вообще не использует fake.

Пример теста, где тестовый класс X используется в качестве макета:

const pleaseReturn5 = 5;
var fake = new FakeX(pleaseReturn5);
var cut = new ClassUnderTest(fake);

cut.SquareIt;

Assert.AreEqual(25, fake.SomeProperty);

В этом случае Assert проверяет значение на fake, что делает его фиктивным.

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

Я согласен с Ошерове, что

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

Утверждение против фальшивки - это то, чего вы действительно хотите избежать, так как ваши тесты сильно зависят от реализации класса, который вообще не тестируется. Это означает, что тесты для класса ActualClassUnderTest могут начать ломаться, потому что изменилась реализация для ClassUsedAsMock. И это вызывает неприятный запах для меня. Тесты для ActualClassUnderTest предпочтительно должны ActualClassUnderTest только при изменении ActualClassUnderTest.

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

Чтобы получить удовольствие от прочтения того, почему вы должны избегать насмешек, как здесь определено, поищите в Google "fowler mockist classicist". Вы найдете множество мнений.

Ответ 4

Как отмечается в ответе, получившем наибольшее количество голосов, Мартин Фаулер обсуждает эти различия в Mocks, не являются заглушками, и, в частности, подзаголовок "Разница между Mocks и заглушками", поэтому обязательно прочитайте эту статью.

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

Подделки

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

Одним из примеров подделки является база данных в памяти (например, использование sqlite с :memory: store). Вы никогда не будете использовать это для производства (так как данные не сохраняются), но это совершенно адекватно в качестве базы данных для использования в среде тестирования. Это также намного легче, чем "настоящая" база данных.

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

В качестве третьего примера представьте объект, который предоставляет API кеша; объект, который реализует правильный интерфейс, но просто не выполняет никакого кэширования, но всегда возвращает промах кэша, будет своего рода подделкой.

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

Столбики

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

Цель заглушки - привести тестируемую систему в определенное состояние. Например, если вы пишете тест для некоторого кода, который взаимодействует с REST API, вы могли бы заглушить REST API с помощью API, который всегда возвращает постоянный ответ или который отвечает на запрос API с определенной ошибкой. Таким образом, вы могли бы написать тесты, которые утверждают, как система реагирует на эти состояния; например, тестирование ответа, который получают ваши пользователи, если API возвращает ошибку 404.

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

Mocks

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

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

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

Тест удваивается

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

Ответ 5

Чтобы проиллюстрировать использование заглушек и макетов, я хотел бы также привести пример, основанный на Рое Ошерове " Искусство модульного тестирования ".

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

Вот логика, которую мы хотели бы проверить внутри LogAnalyzer:

if(fileName.Length<8)
{
 try
  {
    service.LogError("Filename too short:" + fileName);
  }
 catch (Exception e)
  {
    email.SendEmail("a","subject",e.Message);
  }
}

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

  • Как мы можем заменить веб-сервис?

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

  • Как мы узнаем, что служба электронной почты была вызвана правильно или вообще?

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

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

[TestFixture]
public class LogAnalyzer2Tests
{
[Test]
 public void Analyze_WebServiceThrows_SendsEmail()
 {
   StubService stubService = new StubService();
   stubService.ToThrow= new Exception("fake exception");
   MockEmailService mockEmail = new MockEmailService();

   LogAnalyzer2 log = new LogAnalyzer2();
   log.Service = stubService
   log.Email=mockEmail;
   string tooShortFileName="abc.ext";
   log.Analyze(tooShortFileName);

   Assert.AreEqual("a",mockEmail.To); //MOCKING USED
   Assert.AreEqual("fake exception",mockEmail.Body); //MOCKING USED
   Assert.AreEqual("subject",mockEmail.Subject);
 }
}

Ответ 6

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

Ответ 7

Если вы знакомы с Arrange-Act-Assert, то один из способов объяснить разницу между заглушкой и макетом, которая может оказаться полезной для вас, состоит в том, что заглушки принадлежат разделу упорядочения, так как они предназначены для упорядочения входного состояния, а макеты принадлежат раздел assert, как они для утверждения результатов против.

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

Ответ 8

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

Ответ 9

Я многому научился на следующем ресурсе с превосходным объяснением Роберта К. Мартина (дядя Боб):

Маленький Пересмешник на Чистом Блоге Кода

Это объясняет различия и тонкости

  • манекены
  • двойной тест
  • заглушки
  • шпионы
  • (правда) издевается
  • подделками

В нем также упоминается Мартин Фаулер, и он объясняет немного истории тестирования программного обеспечения.

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

Ответ 10

stub и fake являются объектами в том смысле, что они могут варьировать свой отклик в зависимости от входных параметров основное различие между ними заключается в том, что Fake ближе к реальной реализации, чем заглушка. Заглушки содержат в основном жестко запрограммированные ответы на ожидаемый запрос. Давайте посмотрим на пример:

public class MyUnitTest {

 @Test
 public void testConcatenate() {
  StubDependency stubDependency = new StubDependency();
  int result = stubDependency.toNumber("one", "two");
  assertEquals("onetwo", result);
 }
}

public class StubDependency() {
 public int toNumber(string param) {
  if (param == "one") {
   return 1;
  }
  if (param == "two") {
   return 2;
  }
 }
}

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

public class MockADependency {

 private int ShouldCallTwice;
 private boolean ShouldCallAtEnd;
 private boolean ShouldCallFirst;

 public int StringToInteger(String s) {
  if (s == "abc") {
   return 1;
  }
  if (s == "xyz") {
   return 2;
  }
  return 0;
 }

 public void ShouldCallFirst() {
  if ((ShouldCallTwice > 0) || ShouldCallAtEnd)
   throw new AssertionException("ShouldCallFirst not first thod called");
  ShouldCallFirst = true;
 }

 public int ShouldCallTwice(string s) {
  if (!ShouldCallFirst)
   throw new AssertionException("ShouldCallTwice called before ShouldCallFirst");
  if (ShouldCallAtEnd)
   throw new AssertionException("ShouldCallTwice called after ShouldCallAtEnd");
  if (ShouldCallTwice >= 2)
   throw new AssertionException("ShouldCallTwice called more than twice");
  ShouldCallTwice++;
  return StringToInteger(s);
 }

 public void ShouldCallAtEnd() {
  if (!ShouldCallFirst)
   throw new AssertionException("ShouldCallAtEnd called before ShouldCallFirst");
  if (ShouldCallTwice != 2) throw new AssertionException("ShouldCallTwice not called twice");
  ShouldCallAtEnd = true;
 }

}

Ответ 11

Stub, Fakes и Mocks имеют разные значения в разных источниках. Я предлагаю вам ввести внутренние условия вашей команды и согласовать их значение.

Я думаю, что важно различать два подхода:  - проверка поведения (подразумевается подмена поведения)  - проверка конечного состояния (подразумевает эмуляцию поведения)

Рассмотрим отправку электронной почты в случае ошибки. При выполнении проверки поведения - вы проверяете, что метод Send из IEmailSender был выполнен один раз. И вам нужно эмулировать результат возврата этого метода, вернуть идентификатор отправленного сообщения. Итак, вы говорите: "Я ожидаю, что Send будет вызван. И я просто верну фиктивный (или случайный) Id для любого вызова". Это проверка поведения: emailSender.Expect(es=>es.Send(anyThing)).Return((subject,body) => "dummyId")

При выполнении проверки состояния вам нужно будет создать TestEmailSender, который реализует IEmailSender. И внедрить метод Send - сохраняя входные данные в некоторой структуре данных, которая будет использоваться для будущей проверки состояния, например, массив некоторых объектов SentEmails, а затем он проверяет, что вы убедитесь, что SentEmails содержит ожидаемую электронную почту. Это проверка состояния: Assert.AreEqual(1, emailSender.SentEmails.Count)

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