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

StackOverflow https://stackoverflow.com/questions/346372

Вопрос

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

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

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

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

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

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

Это было полезно?

Решение

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

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

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

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

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

От xunitpattern:

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

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

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

Лично

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

Пример теста, в котором класс 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, превращая эту фальшивку в насмешку.

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

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

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

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

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

Чтобы интересно прочитать о том, почему вам следует избегать издевательств, как они определены здесь, введите в Google фразу «фантаст-моксист-классик».Вы найдете множество мнений.

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

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

Подделки

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

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

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

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

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

Столбики

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

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

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

Mocks

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

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

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

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

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

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

Представьте себе, что у нас есть приложение 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);
 }
}

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

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

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

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

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;
 }

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top