Какова цель ложных объектов?

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

Ответ 1

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

Тестирование устройств

Представьте модульное тестирование для этой системы:

cook <- waiter <- customer

Как правило, легко предвидеть тестирование низкоуровневого компонента, такого как cook:

cook <- test driver

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

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

cook <- waiter <- test driver

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

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

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

    -----------------------
   |                       |
   v                       |
test cook <- waiter <- test driver

Здесь тестовый повар "в сговоре" с тестовым драйвером. В идеальном случае тестируемая система разработана таким образом, что тестовый повар может быть легко заменен (injected) для работы с официантом без изменения производственного кода (например, без изменения кода официанта).

Макетные объекты

Теперь тестовый кук (тестовый двойной) может быть реализован по-разному:

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

Смотрите статью Фаулера для более подробной информации о подделках против окурков против mocks vs dummies, но пока давайте сосредоточимся на макете.

    -----------------------
   |                       |
   v                       |
mock cook <- waiter <- test driver

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

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

Разговор, связанный с тестированием с макетами, может выглядеть так:

тестовый драйвер mock cook: ожидайте порядка хот-догов и дайте ему эту фиктивную хот-дог в ответ

тестовый драйвер (позиционирующий себя как клиент) официант: мне нужна хот-дог, пожалуйста... официант до mock cook: 1 хот-дог, пожалуйста,
mock cook официант: заказывайте: готовят одну готовую собаку (дайте фиктивной хот-доги официанту)
официант для тестового драйвера: вот ваша хот-дог (дает фиктивную хот-дог для тестирования драйвера)

тестовый драйвер: ТЕСТ УСПЕШЕН!

Но так как наш официант новый, это может произойти:

тестовый драйвер mock cook: ожидайте порядка хот-догов и дайте ему эту фиктивную хот-дог в ответ

тестовый драйвер (позиционирующий себя как клиент) официант: мне нужна хот-дог, пожалуйста... официантаto mock cook: 1 гамбургер, пожалуйста,
mock cook останавливает тест: мне сказали ожидать хот-дога!

тестовый драйвер отмечает проблему: TEST FAILED! - официант изменил порядок

или

тестовый драйвер mock cook: ожидайте порядка хот-догов и дайте ему эту фиктивную хот-дог в ответ

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

тестовый драйвер отмечает неожиданный картофель фри: TEST FAILED! официант вернул неправильное блюдо

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

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

Ответ 2

A Mock Object - объект, который заменяет реальный объект. В объектно-ориентированном программировании имитируемые объекты имитируют объекты, имитирующие поведение реальных объектов контролируемыми способами.

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

http://en.wikipedia.org/wiki/Mock_object

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

Слово "Mock" иногда ошибочно используется как "Stub". Различия между двумя словами: описанный здесь. По сути, макет - это объект-заглушка, который также включает в себя ожидания (т.е. "Утверждения" ) для правильного поведение испытуемого объекта/метода.

Например:

class OrderInteractionTester...
  public void testOrderSendsMailIfUnfilled() {
    Order order = new Order(TALISKER, 51);
    Mock warehouse = mock(Warehouse.class);
    Mock mailer = mock(MailService.class);
    order.setMailer((MailService) mailer.proxy());

    mailer.expects(once()).method("send");
    warehouse.expects(once()).method("hasInventory")
      .withAnyArguments()
      .will(returnValue(false));

    order.fill((Warehouse) warehouse.proxy());
  }
}

Обратите внимание, что объекты warehouse и mailer mock запрограммированы с ожидаемыми результатами.

Ответ 3

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

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

Ответ 4

Объект Mock является одним из Test Double. Вы используете mockobjects для проверки и проверки протокола/взаимодействия тестируемого класса с другими классами.

Как правило, вы будете выглядеть как "программа" или "запись": вызовы методов, которые вы ожидаете от своего класса, к базовому объекту.

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

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

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

Widget sampleWidget = new Widget();
WidgetDao mock = createMock(WidgetDao.class);
WidgetService svc = new WidgetService(mock);

// record expected calls on the dao
expect(mock.getById(id)).andReturn(sampleWidget);   
expect(mock.save(sampleWidget);

// turn the dao in replay mode
replay(mock);

svc.updateWidgetPrice(id,newPrice);

verify(mock);    // verify the expected calls were made
assertEquals(newPrice,sampleWidget.getPrice());

Таким образом, мы можем легко протестировать разработку дисков классов, которые зависят от других классов.

Ответ 6

Когда модуль тестирует часть компьютерной программы, вы в идеале хотите протестировать только поведение этой конкретной части.

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

If theUserIsFred then
    Call Printer(HelloFred)
Else
   Call Printer(YouAreNotFred)
End

Если вы тестировали это, вы бы хотели протестировать часть, которая смотрит, если пользователь Fred или нет. Вы действительно не хотите проверять часть вещей Printer. Это будет еще одно испытание.

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


Существует несколько других типов притворенных объектов, которые вы можете использовать, а не Mocks. Главное, что делает Mocks Mocks в том, что они могут быть настроены с поведением и ожиданиями.

Ожидания позволяют вашему Mock поднять ошибку, если она используется неправильно. Таким образом, в приведенном выше примере вы можете быть уверены, что принтер вызывается с помощью HelloFred в тестовом примере "user is Fred". Если этого не произойдет, ваш Mock может предупредить вас.

Поведение в Mocks означает, что, например, ваш код сделал что-то вроде:

If Call Printer(HelloFred) Returned SaidHello Then
    Do Something
End

Теперь вы хотите проверить, что делает ваш код при вызове принтера и возвращает SaidHello, поэтому вы можете настроить Mock для возврата SaidHello, когда он вызывается с помощью HelloFred.

Один хороший ресурс вокруг этого - сообщение Мартина Фаулерса Mocks не являются штампами

Ответ 7

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

Вкратце, вы используете заглушки для нарушения зависимости SUT (System Under Test) от других объектов и макетов, чтобы сделать это и, чтобы проверить, что SUT вызвал определенные методы/свойства в зависимости. Это восходит к основополагающим принципам модульного тестирования: тесты должны быть легко читаемыми, быстрыми и не требующими конфигурации, которые могут подразумевать использование всех реальных классов.

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

Простой сценарий с использованием С# и Moq:

public interface IInput {
  object Read();
}
public interface IOutput {
  void Write(object data);
}

class SUT {
  IInput input;
  IOutput output;

  public SUT (IInput input, IOutput output) {
    this.input = input;
    this.output = output;
  }

  void ReadAndWrite() { 
    var data = input.Read();
    output.Write(data);
  }
}

[TestMethod]
public void ReadAndWriteShouldWriteSameObjectAsRead() {
  //we want to verify that SUT writes to the output interface
  //input is a stub, since we don't record any expectations
  Mock<IInput> input = new Mock<IInput>();
  //output is a mock, because we want to verify some behavior on it.
  Mock<IOutput> output = new Mock<IOutput>();

  var data = new object();
  input.Setup(i=>i.Read()).Returns(data);

  var sut = new SUT(input.Object, output.Object);
  //calling verify on a mock object makes the object a mock, with respect to method being verified.
  output.Verify(o=>o.Write(data));
}

В приведенном выше примере я использовал Moq, чтобы продемонстрировать заглушки и издевки. Moq использует тот же класс для обоих - Mock<T>, что делает его немного запутанным. Независимо от того, во время выполнения тест завершится с ошибкой, если output.Write не вызывается с данными как parameter, тогда как отказ вызова input.Read() не подведет его.

Ответ 8

Как еще один ответ, предложенный по ссылке "" Mocks Are not Stubs ", mocks - это форма" тестового двойника" для использования вместо реального объекта. То, что отличает их от других форм двойных тестов, таких как объекты-заглушки, состоит в том, что другие тестовые двойники предлагают проверку состояния (и, возможно, имитацию), тогда как mocks предлагает проверку поведения (и, возможно, симуляцию).

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

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

Ответ 9

Часть моментов использования макетных объектов заключается в том, что они не должны быть реализованы в соответствии со спецификацией. Они могут просто дать фиктивные ответы. Например. если вам нужно реализовать компоненты A и B и оба "вызвать" (взаимодействовать) друг с другом, тогда вы не сможете проверить A до тех пор, пока не будет реализован B, и наоборот. В тестовой разработке это проблема. Таким образом, вы создаете объекты mock ("dummy") для A и B, которые очень просты, но они дают какой-то ответ, когда они взаимодействуют. Таким образом, вы можете реализовать и протестировать A, используя макет объекта для B.

Ответ 10

Для php и phpunit хорошо объяснено в документации phpunit. глянь сюда документация phpunit

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