Що таке глузування?


532

Що таке глузування? .


3
Також дивіться тут stackoverflow.com/questions/3622455/…
мед

1
Engineering.pivotal.io/post/the-test-double-rule-of-thumb має широкий огляд різних типів тестових пар (включаючи макети), а також те, що вам слід використовувати, коли
carpeliam

Відповіді:


598

Пролог: Якщо ви подивитесь на макет іменника у словнику, ви побачите, що одне з означень цього слова є чимось зробленим як наслідування .


Знущання в основному застосовуються при тестуванні одиниць. Об'єкт, що тестується, може мати залежність від інших (складних) об'єктів. Для ізоляції поведінки об'єкта ви хочете замінити інші об'єкти макетами, що імітують поведінку реальних об'єктів. Це корисно, якщо реальні об’єкти не доцільно включати в одиничний тест.

Коротше кажучи, глузування - це створення об’єктів, що імітують поведінку реальних об'єктів.


Часом ви можете розрізняти глузування на відміну від заглушки . З цього приводу може виникнути незгода, але моє визначення заглушки - це «мінімально» змодельований об’єкт. Заглушка реалізує достатньо поведінки, щоб дозволити досліджуваному об'єкту виконати тест.

Макет - це як заглушка, але тест також перевірить, що тестуваний об'єкт викликає макет, як очікувалося. Частина тесту - це перевірка правильності використання макета.

Щоб навести приклад: Ви можете заглушити базу даних, застосувавши просту структуру пам'яті для зберігання записів. Об'єкт, що перевіряється, може потім читати і записувати записи в заглушку бази даних, щоб дозволити йому виконати тест. Це може перевірити деяку поведінку об'єкта, не пов’язаного з базою даних, і заглушка бази даних буде включена лише для того, щоб тест запустився.

Якщо ви хочете перевірити, чи перевіряється об'єкт записує певні дані в базу даних, вам доведеться знущатися над базою даних. Потім ваш тест включав би твердження про те, що було написано в макет бази даних.


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, дані АБО у разі відмови, ви передаєте потрібну errorString, HTTPResponse), яка вам потрібна, а потім перевіряєте знущається клас.

Коротше кажучи, глузування - це спростити та обмежити тестування, а також змусити вас годувати те, від чого залежить клас. У цьому прикладі ви уникаєте тестування самих мережевих дзвінків і замість цього перевіряєте, чи працює ваш додаток так, як ви очікуєте, з ін'єкційними виходами / відповідями - глузуючи з класів

Потрібно сказати, що ви перевіряєте кожну мережеву відповідь окремо.


Тепер питання, яке я завжди мав на увазі, було: договори / кінцеві пункти і в основному відповідь JSON моїх API постійно оновлюються. Як я можу написати одиничні тести, які враховують це?

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

Це відповідальність розробника бекенда за оновлення макетів. Чи повинно бути частиною нашої угоди про те, що вони надають оновлені макети?

Відповідь на вищезазначене питання полягає в тому, що: тестові одиниці + ваш процес розробки як розробника на стороні клієнта повинен / захопить застарілий насмішок. Якщо ви запитаєте мене як? добре відповідь:

Наше фактичне додаток не зможе (або не вийде з ладу, але не матиме бажаної поведінки) без використання оновлених API ... отже, якщо це не вдасться ... ми внесемо зміни в наш код розробки. Що знову ж таки призводить до того, що наші тести провалюються .... що нам доведеться виправити. (Насправді, якщо ми хочемо виконати процес TDD правильно, ми не повинні писати жодного коду про поле, якщо ми не пишемо тест для нього ... і побачимо, що він не працює, а потім перейти і написати фактичний код розробки для нього.)

Це все означає, що бекенду не потрібно говорити: «Ей, ми оновили макети» ... це врешті-решт відбувається через розробку / налагодження вашого коду. ‌ّ Тому що це все є частиною процесу розробки! Хоча якщо бекенд надає вам насмішку у відповідь, тоді це простіше.

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

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


Лише для розробників iOS:

Дуже хороший приклад глузування - це практичні протокольні розмови Наташі Муращев . Просто перейдіть до хвилини 18:30, хоча слайди можуть не синхронізуватися з фактичним відео video

Мені дуже подобається ця частина із стенограми:

Оскільки це тестування ... ми хочемо переконатися, що getфункція з Gettableвиклику викликається, тому що вона може повернутися і функція теоретично може призначити масив продуктів харчування з будь-якого місця . Нам потрібно переконатися, що воно називається;


3
Чудовий приклад, я просто додам, що в цьому конкретному прикладі підклас виступає як макет, але цей приклад також використовує заглушку. Жорстко кодовані відповіді JSON вважаються заглушеними відповідями. Я додаю це лише тому, що розрізнити макети та заглушки важко, але цей приклад чітко показує, як обидва можна використовувати разом.
користувач3344977

Відмінне пояснення, дякую. Один невеликий твір до питання про зміну API. Що робити, якщо це не ваш API, щоб ви не були частиною процесу розробки? Я хочу знати, коли моя бібліотека клієнтів виходить з ладу.
ThinkDigital

@ThinkDigital Good API мають хороші примітки до випуску та повідомляють про зміни правильно, якщо у вас немає цього каналу, то, можливо, прийшов час вам засісти на зустрічі та обговорити її | хороші розробники завжди будуть розглядати зміни API нової версії та уникати просто оновлення версії API. У вас є версії API? Якщо жоден з них не піймає цього, то після QAing ви дізнаєтесь, а потім оновіть свої тести ← обов'язок всієї команди. → обов'язок єдиного диявола: мало би турбуватися. Просто обробіть випадок, коли сервер повертає помилку, або сервер не повертає помилку, але не може розібрати json або обробити правильний регістр.
Мед

Дякуємо за відповідь, @Honey! У моєму випадку я підтримую клієнта для pub.dev , у якого є API, але він сильно бракує. Настільки, що краще було зробити API, обрізавши їх сайт, ніж використовувати їх офіційний API. Через це зміни на сайті можуть порушити код, і в цьому випадку їм не потрібно буде заважати оновлювати когось. Сайт є відкритим кодом, але інша річ - підтримка API, заснованого на змінах, які вносяться на більш тривіальній основі.
ThinkDigital

32

В Інтернеті є багато відповідей на ТА та хороших дописів про глузування. Одне з місць, яке ви можете почати шукати - це повідомлення Мартіна Фаулера Mocks Ant't Stubs, де він обговорює багато ідей знущань.

В одному абзаці - глузування - це одна особлива методика, яка дозволяє перевірити одиницю коду, не залежачи від залежностей. Загалом, те, що відрізняє глузування від інших методів, полягає в тому, що макетні об'єкти, які використовуються для заміни кодових залежностей, дозволять встановити очікування - макетний об’єкт буде знати, як це означає, щоб викликати ваш код і як відповісти.


У вашому оригінальному запитанні згадувався TypeMock, тому я залишив свою відповідь на це нижче:

TypeMock - це назва комерційного глузування .

Він пропонує всі функції вільних глузливих фреймворків, як RhinoMocks і Moq, а також деякі більш потужні варіанти.

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

Як сказано в іншій відповіді, "TypeMocking" насправді не є визначеним поняттям, але його можна вважати типом глузування, який пропонує TypeMock, використовуючи CLR-профілер для перехоплення .Net дзвінків під час виконання, надаючи набагато більшу можливість підробляти об'єкти (не вимоги наприклад, потрібні інтерфейси або віртуальні методи).


@Masoud ніколи не згадував TypeMock. Його питання стосувалося "типу глузування" взагалі.
Пітер Ліллевольд

4
@Peter - як сказано в іншому коментарі, перевірте історію редагування питання. Я не дуже багато можу зробити, якщо я опублікую відповідь, і тоді оригінальне запитання буде повністю змінено.
Девід Холл

9

Макет - це метод / об’єкт, який моделює поведінку реального методу / об’єкта контрольованими способами. Об'єкти макету використовуються при тестуванні одиниць.

Часто метод під тестом викликає інші зовнішні служби або методи, що знаходяться в ньому. Вони називаються залежностями. Після того, як знущалися, залежності поводяться так, як ми їх визначили.

Оскільки залежності контролюються знущами, ми можемо легко перевірити поведінку методу, який ми закодували. Це модульне тестування.

Яке призначення знущань над об’єктами?

Знущається проти заглушок

Одиничні тести проти функціональних тестів


7

Знущання - це генерування псевдооб'єктів, що імітують реальну поведінку об'єктів для тестів


5

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

EDIT : Оскільки в оригінальній редакції згадується "тип глузування", у мене склалося враження, що це стосується TypeMock. На мій досвід, загальний термін - це просто "глузуючий". Будь ласка, нехтуйте наведеною нижче інформацією спеціально щодо TypeMock.

TypeMock Isolator відрізняється від більшості інших глузливих фреймворків тим, що він працює на моєму модифікуванні IL під час польоту. Це дозволяє йому глумати типи та випадки, з яких більшість інших фреймворків не можуть знущатися. Щоб знущатися над цими типами / екземплярами з іншими рамками, ви повинні надати власні абстракції та знущатися над ними.

TypeMock пропонує велику гнучкість за рахунок чистого середовища виконання. Як побічний ефект від того, як TypeMock досягає своїх результатів, іноді ви отримаєте дуже дивні результати при використанні TypeMock.


@Masoud ніколи не згадував TypeMock. Його питання стосувалося "типу глузування" взагалі.
Пітер Ліллевольд

1
@Peter: Первісне формулювання було "що таке глузування?".
Брайан Расмуссен

Я знаю. Оскільки "глузування типу" не еквівалентно типу "TypeMock", я вважаю, що і ваша відповідь, і відповідь @Oded досить відмічені.
Пітер Ліллевольд

1
@ Peeter: На моєму досвіді загальний термін "глузуючий", але в будь-якому випадку я оновив свою відповідь, щоб сподіватися зробити це зрозумілим. Дякуємо за вклад.
Брайан Расмуссен

3

Я думаю, що використання глузуючої рамки ізолятора TypeMock було б TypeMocking.

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


@Masoud ніколи не згадував TypeMock. Його питання стосувалося "типу глузування" взагалі.
Пітер Ліллевольд

3
Власне, первісне запитання включало слово "Тип" перед "глузуванням", але воно було згодом відредаговано. Ось чому частина відповідей містить конкретну інформацію про TypeMock.
Мартін Ліверсайз

1

Якщо ваш макет передбачає мережевий запит, інша альтернатива - це мати справжній тестовий сервер, на який потрібно звернутись. Ви можете використовувати цю послугу для створення запиту та відповіді для вашого тестування. http://testerurl.com/


Я просто спробував отримати доступ до нього, і це зайняло кілька хвилин. Хто скаже, що це також не таємна реєстрація запитів? Нарешті, це може бути краще як коментар :)
Кірен Джонстон

Я насправді зняв його, оскільки не відчував, як перенести його на безкоштовний хостинг. так, це повинен був бути коментарем. це відкритий код, тому, якщо є занепокоєння щодо запитів реєстрації даних, ви можете запустити свій власний. github.com/captainchung/TesterUrl
Меттью Чунг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.