Яка різниця між макетом та заглушкою?


962

Я читав різні статті про знущання проти заїкання в тестуванні, включаючи "Наслідки Мартіна Фаулера не є заготовками" , але все ще не розумію різниці.



75
@OP Тому що різниці немає. Ця стаття, настільки, як її любить громада, - при всій повазі - робить все непотрібним заплутаним, додаючи додаткове значення словам, які легко зрозуміти інакше, і ускладнюючи речі непотрібними. Макет - це просто глузування, те, що керується фальшивою діловою логікою замість реальної. Перевірка поведінки врешті-решт - це ваш вибір, але це все-таки макет. Або все, що ви хочете назвати, але зробіть це ОДНИМ. Не розщеплюйте волоски. Нехай це буде просто, щоб люди могли легко зрозуміти вашу концепцію - з чим вище стаття не вдається.
1616

10
"Класифікація між макетами, підробками та заглушками є суперечливою у всій літературі". З багатьма цитатами. Ще одна з моїх улюблених цитат у Вікіпедії - якщо така річ існує :) en.wikipedia.org/wiki/Mock_object
JD.

11
що статтю Мартіна Фаулера справді важко зрозуміти для початківців.
lmiguelvargasf

1
Я розумію, що заглушка буде просто викинутим об'єктом для вашого тесту, як збірка фіктивних даних. Mock - це вміло переосмислена версія чогось більш складного, наприклад, сервісного рівня з різними методами, якими ви могли змінити поведінку для своїх тестів. Ці дві речі використовуються разом, як ви можете передати деякі застряглі предмети у ваш глузливий шар.
JsonStatham

Відповіді:


746

Стуб

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

Знущаються

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

Різниця між макетами та заглушками

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

Подібність між Макетами та Стубсами

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


876

Передмова

Існує кілька визначень об'єктів, які не є реальними. Загальний термін - тест подвійний . Цей термін охоплює: манекен , фейк , заглушка , глузування .

Довідково

Відповідно до статті Мартіна Фаулера :

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

Стиль

Mocks vs Stubs = Тестування на поведінку та державне тестування

Принцип

Згідно з принципом Тестування лише одне на тест , в одному тесті може бути кілька заглушок, але, як правило, є лише один макет.

Життєвий цикл

Тестовий життєвий цикл за допомогою заглушок:

  1. Налаштування - підготуйте об'єкт, який тестується, та його заглушки.
  2. Вправа - перевірити функціональність.
  3. Перевірити стан - Використовуйте твердження для перевірки стану об'єкта.
  4. Teardown - очищення ресурсів.

Тест життєвого циклу з макетами:

  1. Дані про налаштування - підготуйте об'єкт, який тестується.
  2. Очікування від налаштування - підготуйте очікування в макеті, який використовується первинним об'єктом.
  3. Вправа - перевірити функціональність.
  4. Перевірка очікувань - Перевірте, чи правильні методи були викликані в макет.
  5. Перевірити стан - Використовуйте твердження для перевірки стану об'єкта.
  6. Teardown - очищення ресурсів.

Підсумок

Тестування як глузувань, так і заглушок дає відповідь на запитання: Який результат?

Тестування з макетами також цікавить: Як досягнутий результат?


Зачекайте, знущання також повертають консервовані відповіді? Тому що інакше, чому вони відповідають на запитання?
AturSams

З того, що ви написали, я можу сказати, що макети = заглушки + очікування та перевірки, тому що макети "надають консервовані відповіді на дзвінки, здійснені під час тесту, зазвичай взагалі не відповідають на те, що не передбачено для тесту" (те саме, що заглушки). І приклад, який Фаулер показав як приклад заглушки, насправді є прикладом шпигуна! Це означає, що макет - це заглушка, а шпигун - заглушка. А заглушка - це просто предмет, який має кілька методів роботи. Це також пояснює, чому метод Mockito застарілий stub ().
колобок

Що я вважаю заплутаним у цьому, і прийнятою відповіддю є ця «установка очікування», що це навіть означає? Зазвичай у "головному коді" ви створюєте результати, які ви очікували. Здається, ви сподіваєтесь, що ви якось ставитесь до макетного об'єкта, але це не має для мене сенсу. ТАКОЖ, ви можете так само легко здійснити макет з деяким вкладом, зберегти результат, створити «очікування» пізніше і потім порівняти. Ви використовуєте термінологію, яку я вважаю занадто абстрактною та неоднозначною.
IceFire

365

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


33
Я думаю, що це найкоректніше місце у відповіді. Винос: макет IS-A заглушка. stackoverflow.com/a/17810004/2288628 - це довша версія цієї відповіді.
PoweredByRice

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

2
@ dave1010 Mocks, безумовно, може повернути дані або навіть викинути виняток. Вони повинні зробити це у відповідь на передані їм парами.
Трентон

2
@trenton, якщо об'єкт повертається або кидає на основі даних, переданих у ньому, то це підробка , а не макет. Заглушки перевіряють, як ваш SUT обробляє отримання повідомлень, знущається з тестування того, як ваш SUT надсилає повідомлення. Перемішування 2, ймовірно, призведе до поганого дизайну ОО.
dave1010

8
Я думаю, що це чудово - заглушка повертає відповіді на запитання. Макет також повертає відповіді на запитання (is-stub), але він також підтверджує, що запитання було задано !!
Лейф

238

Ось опис кожного з них, а далі - зразок реального світу.

  • Манекен - просто нечіткі значення для задоволення API.

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

  • Підробка - створити тестову реалізацію класу, який може залежати від якоїсь зовнішньої інфраструктури. (Доброю практикою є те, що ваш тестовий пристрій НЕ насправді взаємодіє із зовнішньою інфраструктурою.)

    Приклад : Створіть підроблену реалізацію для доступу до бази даних, замініть її на in-memoryколекцію.

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

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

  • Макет - дуже схожий, Stubале interaction-basedне на державному рівні. Це означає, що ви не розраховуєте Mockповернути якесь значення, але припустити, що здійснюється конкретний порядок викликів методів.

    Приклад: Ви тестуєте клас реєстрації користувача. Після дзвінка Saveслід зателефонувати SendConfirmationEmail.

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


175

У курсі codechool.com тестування рейлів на зомбі , вони дають таке визначення термінів:

Стуб

Для заміни методу кодом, який повертає заданий результат.

Знущаються

Заглушка з твердженням, що метод називається.

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


Щоб доповнити посаду Діллона, подумайте про це, у вас є клас під назвою "MakeACake", який приймає кілька бібліотек: молоко, яйця, цукор, духовка.
aarkerio

139

Заглушки не провалюють ваші тести, знущаються.


2
І я думаю, що це добре, ви знаєте, чи тести мають таку поведінку після рефакторингу.
RodriKing

1
@RodriKing У мене таке ж почуття. Як і у Mock, з будь-якими змінами у виробничому коді - у вас є відповідні зміни до тестового коду. Який біль! За допомогою Stubs здається, що ви продовжуєте тестувати поведінку, тому не потрібно робити мікро змін із тестовим кодом.
tucq88

35

Я думаю, що найпростішу і зрозумілішу відповідь на це питання дає Рой Ошерово у своїй книзі «Мистецтво одиничного тестування» (стор. 85)

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

З іншого боку, тест використовуватиме макетний об’єкт, щоб перевірити, чи не вдався тест чи ні. [...]

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

Це означає, що якщо ви робите твердження проти підробки, це означає, що ви використовуєте підробку як макет, якщо ви використовуєте підробку лише для запуску тесту без твердження над ним, ви використовуєте підробку як заглушку.


2
Я хочу, щоб ваша відповідь знайшла шлях до вершини. Ось Р. Ошерово пояснює це youtu.be/fAb_OnooCsQ?t=1006 .
Майкл Екока

31

Читаючи всі пояснення вище, дозвольте спробувати ущільнитись:

  • Stub : фіктивний фрагмент коду, який дозволяє тестувати, але вам все одно, що з ним відбувається.
  • Макет : фіктивний фрагмент коду, який ви ВЕРИФІЗУвали правильно, як частину тесту.
  • Шпигун : фіктивний фрагмент коду, який перехоплює деякі дзвінки до реального фрагмента коду, що дозволяє перевіряти виклики без заміни всього оригінального об'єкта.

4
Хороша відповідь. Макет звучить досить схоже на Spy, хоча, виходячи з вашого визначення. Було б добре, якби ви оновили свою відповідь, щоб включити ще кілька тестових пар.
Роуан Гонтьє

Я не чув про шпигуна, коли я писав цю відповідь.
О'Руні

23

Макет - це просто тестування поведінки, переконавшись, що певні методи називаються. Stub - це тестова версія (як така) певного об’єкта.

Що означає спосіб Apple?


19
"Що означає спосіб Apple?" Використовуйте Helvetica
kubi


2
Чи допомагає це ситуації?
NebulaFox

21

Якщо ви порівнюєте це з налагодженням:

Stub - це як переконатися, що метод повертає правильне значення

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


20

Використання ментальної моделі дійсно допомогло мені зрозуміти це, а не всі пояснення та статті, які не зовсім «занурилися».

Уявіть, що ваша дитина має на столі скляну тарілку, і він починає грати з нею. Тепер ти боїшся, що вона зламається. Отже, ви даєте йому замість нього пластикову тарілку. Це був би Mock (та ж поведінка, той же інтерфейс, "м'якша" реалізація).

Тепер скажіть, що у вас немає пластикової заміни, тому ви пояснюєте "Якщо ви продовжите грати з ним, вона зламається!". Це Стуб , ви заздалегідь надали стан заздалегідь.

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


19

Я думаю, що найважливіша різниця між ними - їхні наміри.

Дозвольте спробувати пояснити це, ЧОМУ заглушка vs. ЧОМУ глузування

Припустимо, я пишу тестовий код для загального контролера загальної шкали часу свого клієнта 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
  • STUB: Мережеве підключення до API twitter дуже повільне, що робить мій тест повільним. Я знаю, що це повернеться часові рамки, тому я зробив заглушку, що імітує API HTTP twitter, так що мій тест запустить його дуже швидко, і я можу запустити тест, навіть коли я в офлайні.
  • ПІДСУМКА: Я ще не написав жодного з моїх методів інтерфейсу, і я не впевнений, які методи мені потрібно записати для мого об’єкту інтерфейсу. Я сподіваюся знати, як мій контролер співпрацюватиме з моїм об’єктом інтерфейсу, написавши тестовий код.

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

Я пропоную прочитати цю статтю, якщо ви намагаєтесь дізнатися більше про макети: http://jmock.org/oopsla2004.pdf


1
Я думаю, у вас є правильна ідея, але Діллон Кірнс пояснив це набагато чіткіше.
O'Rooney

19

Щоб бути дуже чітким і практичним:

Stub: Клас або об’єкт, який реалізує методи класу / об'єкта, які підробляють, і завжди повертає те, що ви хочете.

Приклад у JavaScript:

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

Макет: Це ж заглушка, але вона додає певної логіки, яка "перевіряє", коли метод викликається, так що ви можете бути впевнені, що якась реалізація викликає цей метод.

Як говорить @mLevan, уявіть, як приклад, що ви тестуєте клас реєстрації користувача. Після дзвінка Зберегти, він повинен зателефонувати 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!');
   }
}

16

Цей слайд дуже добре пояснює основні відмінності.

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

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


Це більш чітке пояснення різниці між ними, ІМО. Для заглушки: тестер візьміть Стуб і використовуйте його безпосередньо всередині тестуваного класу. Але для Mock тестувальник повинен пристосувати спосіб використання об'єкта Mock. У різних випадках вона поводитиметься по-різному. На противагу цьому, не передбачається, що заглушка поводиться по-різному, але використовується як є (мається на увазі повернення одних і тих же даних при кожному контакті)
Dexter

12

Мені подобається пояснення, викладене Роєм Ошеровим [відео посилання] .

Кожен створений клас або об’єкт - це підробка. Це глузування, якщо ви перевіряєте дзвінки проти нього. Інакше його заглушка.


12
  • Стюбс проти маків
    • Заглушки
      1. надати конкретні відповіді на методи викликів
        • Наприклад: myStubbedService.getValues ​​() просто повертає рядок, необхідний для тестуваного коду
      2. використовується кодом, який перевіряється, щоб виділити його
      3. не може пройти тест
        • Наприклад: myStubbedService.getValues ​​() просто повертає скребкове значення
      4. часто реалізують абстрактні методи
    • Знущаються
      1. «суперсет» заглушок; можна стверджувати, що певні методи називаються
        • Наприклад: перевірте, що myMockedService.getValues ​​() викликається лише один раз
      2. використовується для тестування поведінки коду, що перевіряється
      3. може провалити тест
        • Наприклад: перевірте, що myMockedService.getValues ​​() викликався один раз; перевірка не вдається, оскільки мій тестований код не був викликаний myMockedService.getValues ​​()
      4. часто знущається з інтерфейсів

11

перегляньте тестові парні ігри:

  • Підробка : підробки - це об'єкти, які мають робочі реалізації, але не такі, як виробничі. Такі як : реалізація об'єкта або сховища доступу до даних в пам'яті.
  • Stub : Stub - це об'єкт, який містить заздалегідь задані дані та використовує їх для відповіді на дзвінки під час тестів. Такі як : об'єкт, якому потрібно захопити деякі дані з бази даних, щоб відповісти на виклик методу.

  • Знущання : Макети - це об'єкти, які реєструють отримані дзвінки. У тестовому твердженні ми можемо перевірити на Mocks, що всі очікувані дії були виконані. Такі як : функціональність, яка викликає послугу надсилання електронної пошти. для більш просто перевірити це .


1
найкраща відповідь на мій погляд
Еро Стефано

9

А підробка це загальний термін , який може бути використаний для опису або недопалка або фіктивний об'єкта (рукописний чи іншим чином ), тому що вони обидва виглядає як реальний об'єкт.

Чи підробка є заглушкою чи макетом, залежить від того, як вона використовується в поточному тесті. Якщо він використовується для перевірки взаємодії (стверджується проти), це об'єкт макету. Інакше це заглушка.

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

Що гладко означає тестовий запуск?
Приклад прикладу нижче:

 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.SendEMail () , для цього вам потрібно імітувати виняток у вашому методі тестування, тому вам просто потрібно створити клас Fake Stub errorService для імітації цього результату, тоді ваш тестовий код зможе перевірити метод mailService.SendEMail (). Як ви бачите, вам потрібно імітувати результат, який є з іншого класу ErrorService External Dependency.


8

Розробники jMock прямо з паперових макетних ролей, а не об'єктів :

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

Отже, основні відмінності:

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

Підводячи підсумок, одночасно намагаючись розвіяти плутанину з назви статті Фаулера : макети - це заглушки, але вони не лише заглушки .


1
я думаю, ти маєш рацію, але саме тому стаття Фоулера плутає, заголовок статті - "Знущаються не заглушки" ... але вони НЕ ?! ¯_ (ツ) _ / ¯
stonedauwg

@stonedauwg, дійсно, я відредагував свій пост, щоб включити ваш каламбур та уточнення. Сподіваюсь, це допоможе трохи більше.
Дімос

@stonedauwg, макет - це не заглушка, як і прямокутник - це не квадрат. :)
seanriordan08

7

Я читав «Мистецтво одиничного тестування» і натрапляв на таке визначення:

Підробка це загальний термін , який може бути використаний для опису або недопалка або фіктивний об'єкта (рукописний чи іншим чином ), тому що вони обидва виглядає як реальний об'єкт. Чи підробка є заглушкою чи макетом, залежить від того, як вона використовується в поточному тесті. якщо він використовується для перевірки взаємодії (стверджується проти), це макетний об'єкт . Інакше це заглушка .


5

Я натрапив на цю цікаву статтю UncleBob The Little Mocker . Він пояснює всю термінологію дуже легко для розуміння, тому її корисно для початківців. Стаття Мартіна Фаулерса важко читається, особливо для початківців, як я.


4

Стюб допомагає нам провести тест. Як? Він дає значення, які допомагають запустити тест. Ці значення самі по собі не реальні, і ми створили ці значення просто для запуску тесту. Наприклад, ми створюємо HashMap для надання нам значень, подібних до значень у таблиці баз даних. Тому замість прямої взаємодії з базою даних ми взаємодіємо з Hashmap.

Макет - це підроблений об’єкт, який виконує тест. де ми ставимо ствердження.


"Тож замість прямої взаємодії з базою даних ми взаємодіємо з Hashmap." ... тому що, коли ще не було часу кодувати модуль баз даних, ми не змогли запустити тестовий код без використання заглушки. Інакше той самий Hasmap був би глузуванням! правильно?
Борис Даппен

4

Дивіться нижче приклад макетів проти заглушок із використанням C # та Moq Framework. У Moq немає спеціального ключового слова для Stub, але ви можете використовувати об'єкт Mock і для створення заглушок.

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

4

Точка випробування Стюба і Макету:

  • Stub - це фіктивна реалізація, виконана користувачем статичним способом, тобто в написанні програми Stub. Таким чином, він не може обробляти визначення послуги та динамічний стан, як правило, це робиться в рамках JUnit без використання глузливих фреймворків.

  • Мок - це також фіктивна реалізація, але її реалізація робиться динамічним способом, використовуючи схеми Mocking як Mockito. Таким чином, ми можемо обробляти умови та визначення послуги як динамічний спосіб, тобто макети можуть створюватися динамічно з коду під час виконання. Тож за допомогою макету ми можемо динамічно реалізовувати Stubs.


3

Плюс корисних відповідей. Один з найпотужніших моментів використання Mocks, ніж Subs

Якщо співавтор [від якого залежить головний код] не знаходиться під нашим контролем (наприклад, від сторонньої бібліотеки),
в цьому випадку заглушку важче написати, а не знущатися .


2

У своїй відповіді я використав приклади пітона, щоб проілюструвати відмінності.

Stub - 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"

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

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

Детальніше на unittest.mock , зверніть увагу на макет python 2.x не включений у unittest, але це завантажуваний модуль, який можна завантажити через pip (pip install mock).

Я також читав "Мистецтво тестування одиниць" Роя Ошерово, і думаю, що було б чудово, якби подібна книга була написана на прикладах Python та Python. Якщо хтось знає про таку книгу, будь ласка, поділіться. Ура :)


2

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


2

Заглушка - це порожня функція, яка використовується для уникнення необроблених винятків під час тестів:

function foo(){}

Макет - це штучна функція, яка використовується для уникнення залежностей від ОС, середовища та обладнання під час тестів:

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

З точки зору тверджень та стану:

  • Знущання затверджуються перед подією чи зміною штату
  • Заглушки не затверджуються, вони забезпечують стан перед подією, щоб уникнути виконання коду з непов'язаних одиниць
  • Шпигуни налаштовуються як заглушки, а потім стверджуються після події чи зміни стану
  • Підробки не стверджуються, вони запускаються після події з жорстко кодованими залежностями, щоб уникнути стану

Список літератури


2
+1 для додавання шпигунів до словника. Крім того, я думаю, ви маєте на увазі "Шпигуни налаштовані як глузуючі", а не "Шпигуни налаштовують як заглушки"
Sameh Deabes


2

Макет - це як технічний, так і функціональний об’єкт.

Макет технічний . Він справді створений глузуючою бібліотекою (EasyMock, JMockit і останнім часом Mockito відомі цим) завдяки генерації байтових кодів .
Реалізація макету створюється таким чином, щоб ми могли інструментувати це повернення певного значення при застосуванні методу, а також деякі інші речі, такі як перевірка того, що метод макету викликався з певними специфічними параметрами (сувора перевірка) або будь-якими параметрами ( суворої перевірки немає).

Негайний макет:

@Mock Foo fooMock

Запис поведінки:

when(fooMock.hello()).thenReturn("hello you!");

Підтвердження виклику:

verify(fooMock).hello()

Очевидно, це не природний спосіб інстанціювати / переосмислювати клас / поведінку Foo. Тому я посилаюся на технічний аспект.

Але макет є також функціональним, оскільки це екземпляр класу, який нам потрібно ізолювати від SUT. І із зафіксованою поведінкою на ньому, ми могли б використовувати його в SUT так само, як і з заглушкою.


Заглушка - це лише функціональний об’єкт: це екземпляр класу, який нам потрібно ізолювати від SUT, і це все. Це означає, що як клас заглушки, так і всі прилади для поведінки, необхідні під час наших тестів, повинні бути чітко визначені.
Наприклад, для stub hello()потрібно буде підкласифікувати Fooклас (або реалізувати його інтерфейс, у якому він є) та перекрити hello() :

public class HelloStub extends Hello{    
  public String hello { 
      return "hello you!"; 
  }
}

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

public class HelloStub extends Hello{    
  public HelloStub(String helloReturn){
       this.helloReturn = helloReturn;
  }
  public String hello { 
      return helloReturn; 
  }
}

Інший сценарій: якби у мене був метод побічних ефектів (немає повернення) і я перевірив би, що цей метод викликався, я, мабуть, мав би додати булевий або лічильник у класі заглушки, щоб підрахувати, скільки разів був викликаний метод.


Висновок

Заглушка часто вимагає великих накладних витрат / код для написання вашої одиниці тесту. Що макет запобігає завдяки наданню запису / перевірки функцій поза коробкою.
Ось чому в наш час підхід до заглушки рідко застосовується на практиці з появою чудових бібліотек.


Про статтю Мартіна Фаулера: Я не вважаю програмістом-макетом, коли я використовую макети і уникаю заглушок.
Але я використовую макет, коли це дійсно потрібно (дратівливі залежності), і я віддаю перевагу тестовим нарізанням та міні-інтеграційним тестам, коли я тестую клас із залежностями, які знущаються над головою.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.