Что такое издевательство?

Ответы:

599

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


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

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


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

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

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

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

Мартин Ливерсаж
источник
18
Это хороший ответ, но он излишне ограничивает концепцию насмешек объектами . Замена «объекта» на «единицу» сделает его более общим.
Rogério
1
Я понимаю разницу между заглушкой и издевательством. Единственное, что, если вы тестируете свои дела с помощью заглушки, и она проходит, то не можете ли вы сделать вывод, что вы уже используете заглушку, следовательно, вам больше не нужна проверка ?
Мед
91

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

tl; dr Это экземпляр оригинального класса. В него вводятся другие данные, поэтому вы избегаете тестирования внедренных частей и сосредотачиваетесь исключительно на проверке деталей реализации вашего класса / функций.

Простой пример:

class Foo {
    func add (num1: Int, num2: Int) -> Int { // Line A 
        return num1 + num2 // Line B
    }
}

let unit = Foo() // unit under test
assertEqual(unit.add(1,5),6)

Как видите, я не тестирую LineA, т.е. я не проверяю входные параметры. Я не проверяю, чтобы увидеть, являются ли num1, num2 целыми числами. У меня нет никаких утверждений против этого.

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

Очевидно, что на самом деле это может стать намного сложнее. Параметры могут быть пользовательскими объектами, такими как Person, Address или подробности реализации могут быть более одного +. Но логика тестирования была бы такой же.

Некодирующий пример:

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

Теперь ваш менеджер входит в дверь и просит вас протестировать его.

Тогда вы, как разработчик, можете взять с собой 1000 реальных объектов, таких как MacBook Pro, Google Nexus, банан, iPad и т. Д., И протестировать и посмотреть, все ли работает.

Но вы также можете использовать поддельные объекты, такие как MacBook Pro идентичного вида (без реальных внутренних деталей) или пластиковый банан перед ним. Вы можете спасти себя от инвестиций в 1000 настоящих ноутбуков и гниющих бананов.

Дело в том, что вы не пытаетесь проверить, является ли банан поддельным или нет. Не проверяя, является ли ноутбук подделкой или нет. Все , что вы делаете, тестирование , если ваша машина , когда он видит банан было бы сказать , not an electronic deviceи для MacBook Pro было бы сказать: Laptop, Apple. Для машины результат его обнаружения должен быть одинаковым для поддельной / поддельной электроники и реальной электроники

Упомянутая выше логика применима и к модульному тестированию реального кода. То есть функция должна работать точно так же с реальными значениями, которые вы получаете от реального ввода (и взаимодействий) или издевалисьзначения, которые вы вводите во время юнит-тестирования. И так же, как вы избавляете себя от использования настоящего банана или MacBook, с помощью юнит-тестов (и насмешек) вы избавляете себя от необходимости делать что-то, что заставляет ваш сервер возвращать код состояния 500, 403, 200 и т. Д. (Принуждая ваш сервер запускает 500 только тогда, когда сервер не работает, а 200 - когда сервер работает. Запускается 100 тестов, ориентированных на сеть, если вам приходится постоянно ждать 10 секунд между переключением сервера вверх и вниз). Поэтому вместо этого вы вводите / смоделируете ответ с кодом состояния 500, 200, 403 и т. Д. И проверяете свое устройство / функцию с введенным / проверенным значением.

Пример кодирования:

Допустим, вы пишете приложение для iOS и выполняете сетевые вызовы. Ваша задача - протестировать ваше приложение. Тестировать / определять, работают ли сетевые вызовы должным образом, НЕ ВАША ОТВЕТСТВЕННОСТЬ. Это ответственность другой стороны (серверной команды), чтобы проверить это. Вы должны удалить эту (сетевую) зависимость и все же продолжать тестировать весь свой код, который работает вокруг нее.

Сетевой вызов может вернуть различные коды состояния 404, 500, 200, 303 и т. Д. С ответом JSON.

Предполагается, что ваше приложение будет работать для всех из них (в случае ошибок ваше приложение должно выдать ожидаемую ошибку). Что вы делаете с насмешками, так это то, что вы создаете «мнимые - похожие на реальные» сетевые ответы (например, код 200 с файлом JSON) и тестируете свой код, не «совершая реальный сетевой вызов и не ожидая ответа вашей сети». Вы вручную жестко кодируете / возвращаете сетевой ответ для ВСЕХ типов сетевых ответов и смотрите, работает ли ваше приложение так, как вы ожидаете. (вы никогда не принимаете / тестируете 200 с неверными данными, потому что это не ваша ответственность, ваша ответственность состоит в том, чтобы тестировать ваше приложение с правильными 200, или в случае 400, 500 вы проверяете, если ваше приложение выдает правильную ошибку)

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

Чтобы сделать это, вы не можете использовать свой оригинальный код (у исходного кода нет предварительно вставленных ответов, верно?). Вы должны что-то добавить к нему, вставить / вставить те фиктивные данные, которые обычно не нужны (или часть вашего класса).

Таким образом, вы создаете экземпляр исходного класса и добавляете к нему все (в данном случае это сетевой HTTPResponse, data ИЛИ в случае сбоя, вы передаете правильный errorString, HTTPResponse), который вам нужен, и затем проверяете фиктивный класс.

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

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


Теперь вопрос, который я всегда думал, заключался в следующем: контракты / конечные точки и, в основном, ответ JSON моих API постоянно обновляются. Как я могу написать модульные тесты, которые принимают это во внимание?

Чтобы уточнить это: скажем, для модели требуется ключ / поле с именем username. Вы проверяете это, и ваш тест проходит. Через 2 недели сервер меняет название ключа на id. Ваши тесты все еще проходят. правильно? или нет?

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

Ответ на вышеуказанный вопрос заключается в следующем: модульные тесты + ваш процесс разработки в качестве разработчика на стороне клиента должен / будет отлавливать устаревшие смоделированные ответы. Если вы спросите меня, как? хорошо ответ:

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

Все это означает, что бэкэнд не должен говорить: «эй, мы обновили макеты» ... это в конечном итоге происходит через разработку / отладку вашего кода. ‌ّ Потому что это все часть процесса разработки! Хотя, если бэкэнд даст вам надуманный ответ, это будет проще.

Весь мой смысл в этом заключается в том, что (если вы не можете автоматизировать получение обновленного поддельного ответа API), необходимо некоторое человеческое взаимодействие, то есть ручное обновление JSON и проведение коротких собраний, чтобы убедиться, что их значения актуальны, и станут частью вашего процесса

Этот раздел был написан благодаря неспокойной дискуссии в нашей группе по встрече CocoaHead


Только для разработчиков iOS:

Очень хороший пример издевательства - это практическая беседа Наташа Муращева, ориентированная на протокол . Просто перейдите к минуте 18:30, хотя слайды могут не синхронизироваться с реальным видео 🤷‍♂️

Мне очень нравится эта часть из стенограммы:

Поскольку это тестирование ... мы хотим убедиться, что вызывается getфункция из Gettable, потому что она может вернуться, и функция может теоретически назначить массив продуктов из любой точки мира . Нам нужно убедиться, что это называется;

Мед
источник
3
Отличный пример, я бы просто добавил, что в этом конкретном примере подкласс действует как макет, но в этом примере также используется заглушка. Жестко закодированные ответы JSON считаются заглушенными ответами. Я только добавляю это, потому что может быть трудно различить макеты и заглушки, но этот пример ясно показывает, как оба могут использоваться вместе.
user3344977
Отличное объяснение, спасибо. Один небольшой твик к вопросу об изменении API. Что, если это не ваш API, и вы не участвуете в процессе разработки? Я хочу знать, когда моя клиентская библиотека выходит из строя.
ThinkDigital
@ThinkDigital Хорошие провайдеры API имеют хорошие заметки о выпуске и должным образом сообщают об изменениях. Если у вас нет этого канала, то, возможно, пришло время сесть на собрание и обсудить его | Хорошие разработчики всегда будут смотреть на изменения API новой версии и избегать простого обновления версии API. У вас есть версии API? Если ни один из них не поймает его, то после QAing вы узнаете, а затем обновите свои тесты ← обязанности всей команды. → Обязанность одного разработчика: это не должно волновать. Просто обработайте случай, когда сервер возвращает ошибку, или сервер не возвращает ошибку, но не может проанализировать json, или обработайте правильный случай.
Мед
Спасибо за ответ, @Honey! В моем случае, я поддерживаю клиента для pub.dev , у которого есть API, но его сильно не хватает. Настолько, что было бы лучше создать API, очистив их сайт, чем использовать их официальный API. Из-за этого изменения на сайте могут нарушить код, и им не нужно будет беспокоиться об обновлении кого-либо в этом случае. Сайт с открытым исходным кодом, но это совсем другое дело, поддерживая API, основанный на изменениях, сделанных на более тривиальной основе.
ThinkDigital
32

Есть много ответов на SO и хорошие посты в Интернете о насмешках. Одним из мест, которое вы можете начать искать, является пост Мартина Фаулера « Насмешки не заглушки», где он обсуждает множество идей насмешки.

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


Ваш оригинальный вопрос упоминал TypeMock, поэтому я оставил свой ответ на этот вопрос ниже:

TypeMock - это название коммерческого фреймворк- макета .

Он предлагает все функции бесплатных фреймворков, таких как RhinoMocks и Moq, а также некоторые более мощные опции.

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

В другом ответе говорилось, что «TypeMocking» на самом деле не является определенным понятием, но его можно использовать для обозначения типа имитации, которую предлагает TypeMock, с использованием профилировщика CLR для перехвата вызовов .Net во время выполнения, что дает гораздо большую способность к имитации объектов (не требований). такие как необходимость интерфейсов или виртуальных методов).

Дэвид Холл
источник
@Masoud никогда не упоминал TypeMock. Его вопрос был о "типовой насмешке" вообще.
Питер Лиллевольд
4
@Peter - как сказал другой комментарий, проверьте историю редактирования вопроса. Не много я могу сделать, если я отправлю ответ, а затем первоначальный вопрос полностью изменится.
Дэвид Холл
9

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

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

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

Какова цель макет объектов?

Издевается над заглушками

Модульные тесты и функциональные тесты

Венкат Котра
источник
7

Mocking генерирует псевдообъекты, которые имитируют поведение реальных объектов для тестов

лол
источник
5

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

РЕДАКТИРОВАТЬ : С оригинальной формулировкой упоминания "тип издевательства" у меня сложилось впечатление, что это связано с TypeMock. По моему опыту общий термин просто «издевательство». Пожалуйста, не стесняйтесь игнорировать приведенную ниже информацию конкретно о TypeMock.

TypeMock Isolator отличается от большинства других насмешливых фреймворков тем, что он работает с моим изменением IL на лету. Это позволяет имитировать типы и экземпляры, которые большинство других фреймворков не могут имитировать. Чтобы высмеивать эти типы / экземпляры с другими платформами, вы должны предоставить свои собственные абстракции и смоделировать их.

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

Брайан Расмуссен
источник
@Masoud никогда не упоминал TypeMock. Его вопрос был о "типовой насмешке" вообще.
Питер Лиллевольд
1
@Peter: оригинальная формулировка была «что такое шутки?».
Брайан Расмуссен
Я знаю. Так как «типовое издевательство» не эквивалентно «TypeMock», я считаю, что и ваш, и ответ @Oded совершенно не соответствуют действительности.
Питер Лиллевольд
1
@ Петер: По моему опыту, общий термин «насмешливый», но в любом случае я обновил свой ответ, чтобы, надеюсь, прояснить это. Спасибо за вклад.
Брайан Расмуссен
3

Я бы подумал, что использование среды моделирования изолятора TypeMock будет TypeMocking.

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

Одед
источник
@Masoud никогда не упоминал TypeMock. Его вопрос был о "типовой насмешке" вообще.
Питер Лиллевольд
3
На самом деле, первоначальный вопрос включал слово «Тип» перед «Насмешкой», но позже он был отредактирован. Вот почему некоторые ответы содержат конкретную информацию о TypeMock.
Martin Liversage
1

Если ваша имитация связана с запросом по сети, другой альтернативой является использование реального тестового сервера. Вы можете использовать этот сервис для генерации запроса и ответа на ваше тестирование. http://testerurl.com/

foobar8675
источник
Я просто попытался получить к нему доступ, и это заняло несколько минут. Кто сказал, что это не секретная регистрация запросов? Наконец, это может быть лучше в качестве комментария :)
Kieren Johnstone
Я на самом деле снял его, так как не хотел переносить его на бесплатный хостинг. да, это должен был быть комментарий. это открытый исходный код, поэтому, если есть проблема с регистрацией запросов, вы можете запустить свой собственный. github.com/captainchung/TesterUrl
Мэттью Чунг,