В чем разница между mock & stub?

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

30 ответов


заглушки

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

Mock

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

разница

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

сходство

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


предисловие

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

ссылка

по данным статья Мартина Фаулера:

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

стиль

насмешки против заглушек = поведенческое тестирование против государственного тестирования

принцип

по принципу


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


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

  • пустышка - просто фиктивные значения, чтобы удовлетворить API.

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

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

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

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

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

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

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

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


в codeschool.com конечно,тестирование рельсов для зомби, они дают это определение терминов:

заглушки

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

Mock

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

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


заглушки не проваливают ваши тесты, МОК может.


Я думаю, что самый простой и ясный ответ на этот вопрос дается из Рой Osherove в своей книге искусство модульного тестирования (стр. 85)

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

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

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

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


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

позвольте мне попытаться объяснить это Почему стаб и зачем глумиться

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

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

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
  • заглушка: сетевое подключение к twitter API очень медленно, что делает мой тест медленным. Я знаю, что это вернет временные рамки, поэтому я сделал заглушку имитация HTTP twitter API, так что мой тест будет работать очень быстро, и я могу запустить тест, даже если я в автономном режиме.
  • MOCK: я еще не написал ни одного из моих методов UI, и я не уверен, какие методы мне нужно написать для моего объекта ui. Я надеюсь узнать, как мой контроллер будет сотрудничать с моим объектом ui, написав тестовый код.

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

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


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

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


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

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

Mock как на самом деле вступаем в метод и убедившись, что все правильно, прежде чем возвращать правильное значение.


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

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

пример в JavaScript:

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

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

как @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!');
   }
}

читая все объяснения выше, позвольте мне попытаться конденсировать:

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

Мне нравится explanantion потушить Рой Osherove [прямая ссылка].

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


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

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

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

что тест выполняется гладко означает?
Forexample в приведенном ниже коде:

 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.Отправка электронных писем отключена() метод, для этого вам нужно имитировать исключение в методе тестирования, поэтому вам просто нужно создать поддельный класс errorService заглушки для имитации этого результата, а затем ваш тестовый код сможет протестировать mailService.Отправка электронных писем отключена() метод. Как вы видите, вам нужно смоделировать результат, который является результатом другого внешнего класса Errorservice зависимостей.


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

enter image description here

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


прямо из газеты макетные роли, а не объекты, разработчиками jMock :

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

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

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

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


  • заглушки против насмешек
    • заглушки
      1. дать конкретные ответы на вызовы методов
        • ex: myStubbedService.getValues () просто возвращает строку, необходимую для тестируемого кода
      2. используется тестируемым кодом для его изоляции
      3. не удается выполнить тест
        • ex: myStubbedService.getValues () просто возвращает значение stubbed
      4. часто реализовать абстрактный методы
    • глумится
      1. "superset" заглушек; можно утверждать, что некоторые методы вызываются
        • ex: убедитесь, что myMockedService.getValues() вызывается только один раз
      2. используется для проверки поведения тестируемого кода
      3. может не пройти тест
        • ex: убедитесь, что myMockedService.getValues () был вызван один раз; проверка не выполняется, потому что myMockedService.getValues() не был вызван моим тестом код
      4. часто издевается над интерфейсами

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

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

я наткнулся на эту интересную статью UncleBob Маленький Насмешник. Он объясняет всю терминологию в очень простой для понимания манере, поэтому его полезно для начинающих. Мартин Фаулерс статья является трудно читать, особенно для начинающих, как я.


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

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


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

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

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

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

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

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

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 с объектами, а не только с функциями, как показано здесь, а также возвращать значение, чтобы объект mock можно было использовать для замены заглушки для тестирования.

подробнее о unittest.МОК!--21-->, примечание в python 2.X mock не входит в unittest, но является загружаемым модулем, который можно загрузить через pip (pip install mock).

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


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


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

function foo(){}

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

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

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

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

ссылки


много правильных ответов там, но я думаю, стоит упомянуть эту форму дядя Боб: https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html

лучшее объяснение с примерами!


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

модульный тест --> заглушка

модульный тест --> блок --> огрызок!--3-->

модульный тест утверждает результаты и состояние блока

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

Макет похоже на заглушку, только у него также есть методы, которые позволяют определить, что методы, где вызывается Mock. Таким образом, с помощью макета можно проверить, может ли устройство корректно обрабатывать различные возвращаемые значения, а также правильно ли устройство использует collaborator. Например, по значению, возвращаемому из объекта dao, нельзя определить, считывались ли данные из базы данных с помощью инструкции или PreparedStatement. И вы не видите, есть ли связь.метод close () был вызван перед возвращением значения. Это возможно с насмешками. Другими словами, mocks делает это позволяет проверить полное взаимодействие единиц с сотрудником. Не только методы collaborator, возвращающие значения, используемые единицей. Использование макета в модульном тесте может быть выражено следующим образом:

модульный тест -- > mock

модульный тест -- > блок -- > макет

модульный тест утверждает результат и состояние блока

модульный тест утверждает методы, вызванные mock

Подробнее >> здесь


заглушка и макет точки зрения тестирования:

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

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


давайте посмотрим тестовые дубли:

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

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


следующее мое понимание...

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

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


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


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

заглушки - заглушка является допустимой полной рабочей реализацией метода или функции (или группы методы и функции, такие как в случае класса stubbed), который имеет идентичный интерфейс/подпись для метода, функции или группы методов и функций, для которых он stubbing. Реализация stubbed обычно будет делать только то, что приемлемо в контексте модульного теста, то есть она не будет делать IO, например, имитируя поведение вещи, которую она тушит.