Макет фреймворку та фреймворки MS Fakes


99

Трохи заплутався в відмінності фреймворків Mock, таких як NMock і VS 2011 Fakes Framework. Проходячи через MSDN, я розумію, що факси дозволяють знущатися над своїми залежностями так само, як RhinoMock або NMock, однак підхід інший, Fakes генерує код, щоб досягти цієї функціональності, але Mocks Framework не робить. То чи моє розуміння правильне? Файки - це лише інша структура Mock

Відповіді:


189

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

Є три основні відмінності, які я бачу прямо між NMock / RhinoMocks / Moq та MS Fakes Framework:

  • Фреймворк MS використовує генерований код, подібно до Accessors в попередніх версіях Visual Studio замість загальних типів. Коли ви хочете використовувати фейк-фреймворк для залежності, ви додаєте збірку, яка містить залежність, до посилань тестового проекту, а потім клацніть правою кнопкою миші на ньому, щоб генерувати тестові подвійні елементи (заглушки або прокладки). Тоді, коли ви тестуєте, ви фактично використовуєте ці створені класи замість цього. NMock використовує дженерики, щоб досягти того ж (тобто IStudentRepository studentRepository = mocks.NewMock<IStudentRepository>()). На мою думку, рамковий підхід MS Fakes гальмує кодову навігацію та рефакторинг зсередини тестів, оскільки ви насправді працюєте з генерованим класом, а не з реальним інтерфейсом.

  • Підроблені фреймворки MS постачають заглушки і кроти (прокладки), тоді як NMock, RhinoMocks і Moq - все це заглушки і макети . Я дійсно не розумію рішення МС не включати знущань, і я особисто не шанувальник кротів з причин, описаних нижче.

  • За допомогою фейкової системи MS ви надаєте альтернативну реалізацію методів, які ви хочете заглушити. У межах цих альтернативних реалізацій можна вказати повернені значення та відстежити інформацію про те, як або якщо метод викликався. За допомогою NMock, RhinoMocks та Moq ви генеруєте макетний об'єкт, а потім використовуєте цей об'єкт, щоб вказати стержневі значення повернення або відстежувати взаємодії (чи називались способи). Мені здається, що підробка MS підробка більш складна і менш виразна.

Щоб уточнити різницю в тому, що надають рамки: NMock, RhinoMocks і Moq забезпечують два типи тестових пар (заглушки та макети). Рамка підробок містить заглушки та родимки (вони називають їх лайми), і, на жаль, не включає макети. Для того, щоб зрозуміти відмінності та схожість між NMock та MS Fakes, корисно зрозуміти, що таке різні типи парних пар:

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

Ідея заглушок у підробках NMock та MS однакова, але з NMock ви б зробили щось подібне:

Stub.On(mockStudentRepository).Method("DoesStudentExist").Will(Return.Value(true));

І з MSFakes ви зробите щось таке:

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() // Generated by Fakes.
{
    DoesStudentExistInt32 = (studentId) => { return new Student(); }
};

Зауважте у прикладі MS Fakes, що ви створюєте абсолютно нову реалізацію методу DoesStudentExist (Зауважте, що він називається DoesStudentExistInt32, оскільки фейк-фрейм додає типи даних параметрів до імен методу, коли він генерує об'єкти stub, я думаю, це не приховує чіткість тести). Якщо чесно, реалізація NMock також помиляє мене, оскільки для імені методу використовується рядок. (Вибачте, якщо я зрозумів неправильно, як NMock призначений для використання.) Цей підхід дійсно гальмує рефакторинг, і я настійно рекомендую RhinoMocks або Moq через NMock з цієї причини.

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

Expect.Once.On(mockStudentRepository).Method("Find").With(123);

Це ще одна причина, чому я віддаю перевагу RhinoMocks і Moq над NMock, NMock використовує старіший стиль очікування, тоді як RhinoMocks і Moq підтримують підхід Arrange / Act / Assert, де ви вказуєте очікувані взаємодії як твердження в кінці тесту, як це. :

stubStudentRepository.AssertWasCalled( x => x.Find(123));

Ще раз зауважте, що RhinoMocks використовує лямбда замість рядка для ідентифікації методу. MS фейк-фреймс взагалі не дає макетів. Це означає, що у своїх заглушених реалізаціях (див. Опис заглушок вище) ви повинні встановити змінні, які згодом переконаєтесь, що вони встановлені правильно. Це виглядатиме приблизно так:

bool wasFindCalled = false;

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() 
{
    DoesStudentExistInt32 = (studentId) => 
        { 
            wasFindCalled = true;
            return new Student(); 
        }
};

classUnderTest.MethodUnderTest();

Assert.IsTrue(wasFindCalled);

Я вважаю, що цей підхід є дещо заплутаним, оскільки вам потрібно відстежити виклик у заглушці, а потім підтвердити його пізніше в тесті. Я вважаю, що приклади NMock, і особливо RhinoMocks, є більш виразними.

Кроти (Шимс): Чесно кажучи, я не люблю родимок, через їх потенціал до неправильного використання. Одне з речей, яке мені дуже подобається в одиничному тестуванні (і TDD зокрема), - тестування вашого коду допомагає зрозуміти, де ви написали поганий код. Це тому, що перевірити погано записаний код складно. Це не вірно при використанні родимок, тому що родимки фактично розроблені для того, щоб ви могли протестувати на залежності, які не вводяться, або перевірити приватні методи. Вони працюють аналогічно заглушкам, за винятком того, що ви використовуєте ShimsContext так:

using (ShimsContext.Create())
{
    System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}

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

Для отримання додаткової інформації про деякі проблеми, пов’язані з фейками, перегляньте ці повідомлення:

Якщо вам цікаво вивчити RhinoMocks, ось відео з навчального курсу Pluralsight (повне розкриття інформації - я написав цей курс і отримую винагороду за перегляд, але, думаю, це стосується цієї дискусії, тому я включаю її тут):


14
@Jim Я не погоджуюся з тим, що дозволити "перевірити залежності, які не вводяться" - це погано. Навпаки, на практиці ця здатність допомагає уникнути захаращування кодової бази з безліччю безглуздих інтерфейсів та пов'язаної з ними конфігурації / складності "об'єктної проводки". Я вже бачив декілька проектів (як Java, так і .NET), у яких були сотні інтерфейсів Java / C # лише з одним класом реалізації та безліччю непотрібної конфігурації XML (для бобів Spring DI або Web.config для MS Unity рамки). Такі залежності краще не вводити.
Rogério

19
@Rogerio, я працював над декількома проектами з тисячами класів, які відповідають цій моделі, і коли введення залежності робиться правильно (якщо ви використовуєте конфігурацію XML, ви не робите це правильно, імхо), це просто і відносно безболісно. З іншого боку, я працював над системами, які цього не роблять, і зв'язок між класами завжди завдавав мені значного болю. Тестування не є причиною використання ін'єкційних залежностей (хоча це не погана причина). Справжня причина - розпушена муфта. Наявність інтерфейсів, реалізованих одним класом, ніколи не заподіювала мені болю.
Джим Купер

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

4
Моє правило: я використовую Fakes лише тоді, коли мені потрібно Shim загальнодоступний / статичний метод або клас, до якого я не маю доступу для реалізації інтерфейсу. Для всього іншого я використовую Moq. Підробки є повільнішими (тому що підроблені збори потрібно генерувати), і потрібно більше зусиль для кодування, щоб відповідати функціоналу, який ви отримуєте з Moq.
Нік

5
@ CarloV.Dango Перш за все, я прекрасно знаю, що для введення залежностей не потрібні окремі інтерфейси; мій попередній коментар просто натякав на тенденцію до створення таких інтерфейсів при використанні DI. По-друге, "МОК" (інверсія управління) не має нічого спільного з DI! (Перший - про інверсію потоку управління між методами, а другий - про розв’язання залежностей для компонента / об'єкта.) Плутаючи IOC і DI, саме ви виявляєте незнання, а не я; і, чесно кажучи, цей сайт не заслуговує на те, щоб люди ображали інших, тож, будь ласка, давайте тримати його цивільним.
Rogério

23

Ви маєте рацію, але тут є більше. Найважливіші речі, від яких слід відповісти:

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

  2. Підробки та макети корисні для тестування коду, який ви не повинні або не можете змінювати, наприклад:

    • Спадковий код, який не використовує (або ефективно використовує) заглушки
    • API сторонніх розробників
    • Ресурси, для яких у вас немає вихідного коду

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

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

Ефективна реалізація підробок (типи Shims, Mocks і Stub) забирає трохи звикання, але варто вартих зусиль. Я особисто економив тижні часу на розробці, використовуючи типи Shims / Mole, Mocks і Stub. Я сподіваюся, що ви так само розважаєтесь із технологією, як і я!


11
Запропонований на основі відсутності специфіки та деяких термінологічних питань з вашими коментарями до фальсифікатів. Fakes - загальний термін для всіх типів тестових пар, а також назва MS, що використовується для їхньої бібліотеки підробок. У їхній бібліотеці лише Шими - насправді Молі, заглушки - ні. Щодо потреби в прикладах, я хотів би побачити приклад у вашій відповіді, який показує, як створити шим (або заглушку) за допомогою факсів простіше, ніж використовувати Moq. Якщо ви внесете зміни у свою відповідь, щоб вирішити ці проблеми, я зміню свою позицію.
Джим Купер

1
Але додає хорошого виправдання для використання лайм (кротів), тобто код сторонніх розробників, API / SDK API. Справа не лише в тому, коли ви працюєте з власними внутрішніми рішеннями. Тож я наділю вас одним голосом, щоб вирівняти це :-)
Тоні Уолл

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

15

Як я розумію, команда Visual Studio хотіла уникнути конкуренції з різними біблійними макетами, доступними для .NET. МС часто стикається з такими важкими рішеннями. Їх заклинають, якщо вони не забезпечують певної функціональності ("чому MS не надає нам макетну бібліотеку; макети - це така загальна вимога?") І прокляті, якщо вони це роблять ("чому Microsoft діє так агресивно і керує її природних прихильників поза ринком? ") Дуже часто, але не завжди, вони вирішують стримуватися від простого надання власної альтернативи доступним та добре прийнятим технологіям. Це, мабуть, так і тут.

Особливість shim Fakes дійсно, дуже корисна. Звичайно, небезпеки є. Потрібна певна дисципліна, щоб ви використовували це лише там, де це необхідно. Однак це заповнює великий пробіл. Моя основна скарга полягає в тому, що вона надходить лише з Ultimate Edition VS 2012, а тому буде доступна лише для підрозділу спільноти .NET. Яка прикрість.


2
Рамки підробок доступні і з версією Premium.
Завжди програмувач

13

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

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

До речі, якщо ви вже випробовували Moles раніше, Fakes - це по суті те саме, що, нарешті, виходить із Microsoft Research і перетворюється на фактичний продукт.


1
Оновлення: Молі тепер інтегровані в MS Fakes. "Рамка Fakes у Visual Studio 2012 - це наступне покоління Moles & Stubs. Файки відрізняються від Moles, проте для переходу від Moles до Fakes потрібні деякі зміни вашого коду. Рамки Moles не підтримуватимуться у Visual Studio 2012 . " Джерело: research.microsoft.com/en-us/projects/moles
Sire

1

Стосовно фальшивих (Shim + Stub) об'єктів, то це було чітко визначено вище, хоча, мабуть, останній абзац в останньому коментарі узагальнює всю ситуацію.

Хоча багато людей стверджують, що фальшиві (Shim + Stub) об’єкти є хорошими активами, які можна мати в деяких випадках тестування одиниць, недоліком є ​​те, що незалежно від того, чи використовуєте Ви Visual Studio 2012 або Visual Studio 2013, ці параметри доступні ТІЛЬКИ з версіями Premium або Ultimate. IOW, це означає, що ви НЕ будете запускати жодного з цих факсів (Shim + Stub) в будь-якій Pro версії.

Можливо, можливо, ви бачите параметр меню Fakes (Shim + Stub) у версіях Pro, але будьте обережні, є кілька досить шансів, що ви закінчитеся абсолютно нічим ... Це не призведе до помилки компіляції, яка говорить вам про те, що щось важливе відсутня, варіантів просто немає, тому не витрачайте час ...

Це важливий фактор, який слід враховувати в команді розробників, особливо якщо один є одним із версій Ultimate, а всі інші використовують Pro версію ... Moq з іншого боку легко встановлюється через Nuget незалежно від того, яку версію Visual Studio ви використовуєте. У мене не було проблем з використанням Moq, головне з будь-яким інструментом - знати, для чого вони використовуються та як правильно ними користуватися;)


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

@SirXamelot, що не рефакторінга коду ви не можете змінити висновок .net при умови статичних викликів наприклад DateTime.Now або Guid.NewGuid
zaitsman
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.