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

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

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

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

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

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

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


person tvanfosson    schedule 06.12.2008    source источник
comment
Ну, вы в основном сказали все это в своем вопросе :) Я думаю, что это довольно хорошо принятые определения этих терминов   -  person Eran Galperin    schedule 06.12.2008
comment
Определение Fake в Википедии отличается от этого, утверждая, что Fake используется как более простая реализация, например использование базы данных в памяти в тестах вместо реального доступа к базе данных) См. en.wikipedia.org/wiki / Test_double   -  person zumalifeguard    schedule 25.08.2017
comment
Я многому научился из следующего ресурса с прекрасным объяснением Роберта К. Мартина (дяди Боба): Маленький насмешник в блоге о чистом коде. Он объясняет различия и тонкости манекенов, тестовых двойников, заглушек, шпионов, (истинных) моков и фейков. В нем также упоминается Мартин Фаулер и немного объясняется история тестирования программного обеспечения.   -  person Erik    schedule 17.06.2019
comment
testing.googleblog.com/2013/ 07 / (краткое одностраничное резюме).   -  person ShreevatsaR    schedule 04.08.2019
comment
Вот что я могу объяснить: Тестовые двойники: фейки, заглушки и Mocks (сообщение в блоге с примерами)   -  person michal-lipski    schedule 12.05.2020
comment
Не существует общепринятого определения для насмешек и заглушек для модульных тестов - потому что их нет для самого модуля.   -  person Konstantin Ivanov    schedule 17.02.2021


Ответы (13)


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

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

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

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

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

Из xunitpattern:

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

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

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

Лично

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

person Patrick Desjardins    schedule 06.12.2008
comment
Мне кажется, что определения Stub и Fake в цитате xUnitPattern перевернуты по сравнению с цитатой Мартина Фаулера. Кроме того, определения Мартина Фаулера для заглушки и фейка перевернуты по сравнению с определениями в исходном вопросе Тванфоссона. На самом деле есть какие-то общепринятые определения этих двух терминов или это просто зависит от того, с кем вы разговариваете? - person Simon Tewsi; 21.01.2013
comment
+1, потому что я пытаюсь упростить, используя: Mock и Stub. Это отличная идея! - person Brad Cupit; 13.05.2013
comment
Не понимаю, почему использование только Mock и Stub - отличная идея. Каждый тестовый двойник имеет свои цели и, следовательно, свое использование. - person Hector Ordonez; 24.10.2014
comment
Я не вижу разницы между Fake и Mock в определении MF. - person IdontCareAboutReputationPoints; 31.08.2015
comment
@MusuNaji: В определении MF нет никаких ожиданий относительно разговора для Fake, кроме того, что у него есть реализация для его интерфейса. С другой стороны, Mock будет оспорен (был ли этот метод вызван?). - person dbalakirev; 29.11.2017
comment
Лично я не поощряю использование моков. Я видел слишком много тестов, которые ничего не проверяют. Моки позволяют избавиться от неприятных запахов в коде, позволяя тестам обходить проблемы, вместо того, чтобы заставлять разработчика исправлять проблему. Не то чтобы они бесполезны, но чаще всего я вижу, что они связаны с плохими тестами. - person Brill Pappin; 16.09.2019
comment
@Brill Pappin, как вы подходите к интеграционным тестам или e2e без Mocks? - person Luke; 17.04.2020
comment
@Luke, мы говорим здесь о модульных тестах, которые разные. За интеграционным тестом должна стоять реальная система. Однако, если вы можете использовать Mock в своем интеграционном тесте, вы можете использовать подделку или заглушку (в зависимости от вашего определения). если вам нужно использовать макет, то вы вероятно тестируете макет, а не интеграцию. Однако есть одно место, где Mocks действительно пригодятся, - это когда у вас плохо написанный api, который вы не можете легко протестировать. В таких случаях Mocks могут быть вам палкой. ИМО конечно. - person Brill Pappin; 22.04.2020

Заглушка - объект, который предоставляет заранее определенные ответы на вызовы методов.

Мок - объект, на который вы возлагаете ожидания.

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

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

person Mike    schedule 03.03.2011
comment
Может ли кто-нибудь объяснить и определить мне, что такое шаблонный ответ в этом контексте? - person MasterMastic; 24.01.2013
comment
Явное значение, а не вычисляемое значение. - person Mike; 01.02.2013
comment
Наконец-то! Некоторые определения я могу понять! Таким образом, на основе этих определений googletest (gtest) / googlemock (gmock) также позволяет заглушки, так как вы можете создавать EXPECT_CALL()s на имитируемом методе, который форсирует определенные выходные данные на основе определенных входов, используя синтаксис типа .WillOnce(Invoke(my_func_or_lambda_func)) (или с .WillRepeatedly()), прикрепленный к EXPECT_CALL(). Некоторые примеры использования Invoke() можно увидеть в другом контексте внизу моего длинного ответа здесь: stackoverflow.com/a/60905880/4561887. - person Gabriel Staples; 14.04.2020
comment
Документация Gmock для Invoke() находится здесь: github.com/google/googletest/blob/master/googlemock/docs/. В любом случае, вывод таков: mock (gmock) Google позволяет легко создавать как mock , так и stubs, хотя большинство mock-файлов не являются заглушками. - person Gabriel Staples; 14.04.2020
comment
Моки - это надмножество заглушек, они по-прежнему могут возвращать предопределенные ответы, но также позволяют разработчику устанавливать ожидания. Некоторые библиотеки IMO размывают границы всех тестовых манекенов. - person Luke; 17.04.2020
comment
Мне не нравится эта терминология. Этот параметр ожидания для моков является либо неправильной абстракцией, либо слишком специализированным. Вы можете просто создать фиктивный объект, применить к нему какую-нибудь функцию и сравнить результат с известным результатом. Так никогда явно не устанавливается ожидание. Фактически, во многих фреймворках ожидание не рассматривается как часть имитации. - person IceFire; 22.05.2020

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

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

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

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

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

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

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

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

Пример теста, в котором класс 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. Думаю, я твердо с Мартином Фаулером в лагере классицистов (см. «Моки не заглушки» Мартина Фаулера) и, как и Ошеров, избегайте тестирования взаимодействия (которое может быть выполнено только путем утверждения против подделки) в максимально возможной степени.

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

person Marjan Venema    schedule 25.10.2015

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

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

Подделки

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

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

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

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

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

Заглушки

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

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

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

Издевается

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

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

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

Тестовые двойники

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

person Daniel Pryden    schedule 06.03.2019

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

person Arezoo Bagherzadi    schedule 21.07.2018
comment
в то время как другие ответы очень подробны и действительно хороши. этот делает его настолько ясным и легким, что трудно не проголосовать за него. гдж! - person Mario Garcia; 16.08.2019

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

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

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

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

person Sammi    schedule 29.03.2017

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

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

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

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

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

person Marat Gallyamov    schedule 08.09.2019
comment
Действительно хорошо детализированное и четкое определение. - person shyam sundar singh tomar; 11.12.2019

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

person Steve Freeman    schedule 21.05.2009

Unit testing - подход к тестированию, при котором модуль (класс, метод) находится под контролем.

Test double - не первичный объект (из мира ООП). Это реализация, которая создается временно для тестирования, проверки или во время разработки. Типы тестовых пар:

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

  • stub object - это простой объект (0, nil и методы без логики) с дополнительным состоянием, которое предопределено (разработчиком) для определения возвращаемых значений. Обычно создается фреймворком

  • mock object очень похож на stub object, но дополнительное состояние изменяется во время выполнения программы, чтобы проверить, что-то произошло (был вызван метод, аргументы, когда, как часто ...).

  • spy object - реальный объект с частичным издевательством. Это означает, что вы работаете с не двойным объектом, за исключением имитации поведения.

  • dummy object - это объект, который необходим для запуска теста, но ни одна переменная или метод этого объекта не вызывается.

заглушка против макета

сказал Мартин Фаулер

Разница в том, что заглушка использует проверку состояния, а макет использует проверку поведения.

[Mockito mock vs spy]

person yoAlex5    schedule 14.04.2020

Все они называются Test Doubles и используются для внедрения зависимостей, которые нужны вашему тесту.

Подделка

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

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

Пустышка

Шпион

person Abuzeid    schedule 16.12.2020

stub и 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. Большинство имитаторов могут отслеживать, сколько раз был вызван метод, и могут реагировать на эту информацию. Моки обычно знают контекст каждого вызова и могут по-разному реагировать в разных ситуациях. Из-за этого моки требуют некоторого знания класса, над которым они насмехаются. заглушка обычно не может отслеживать, сколько раз был вызван метод или в каком порядке вызывалась последовательность методов. Макет выглядит так:

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

}
person Alireza Rahmani khalili    schedule 12.11.2018

В книге Джерарда Месароса xUnit Test Patterns хорошая таблица, которая дает хорошее представление о различиях

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

person Saeed Alizadeh    schedule 21.04.2021