Як зазвичай зловживають об'єктами знущань?


15

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


це стаття, яку ви читали цю? martinfowler.com/articles/mocksArentStubs.html
keppla

ні ... не можу згадати точне джерело, але опублікую тут, якщо я це зробити
Арман

Мене взяли на себе завдання stackoverflow для знущання над API mongodb. Мене вказували на публікації в блозі, яка стверджувала, що неправильно знущатися над будь-яким класом, який ви самі не писали. Я насправді з цим не згоден, але думка існує.
Кевін

Відповіді:


13

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

public class Person
{
    private readonly string _firstName;
    private readonly string _surname;

    public Person(string firstName, string surname)
    {
        if (String.IsNullOrEmpty(firstName))
        {
            throw new ArgumentException("Must have first name");
        }

        if (String.IsNullOrEmpty(surname))
        {
            throw new ArgumentException("Must have a surname");
        }

        _firstName = firstName;
        _surname = surname;
    }

    public string Name 
    {
        get
        {
            return _firstName + " " + _surname;
        }
    }
}

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

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


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

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

Моє правило завжди було знущатися над поведінкою, а не над даними.
ardave

10

Це може здатися очевидним, але: Не використовуйте макетні об’єкти у виробничому коді! Я бачив не один приклад, коли виробничий код залежав від характеристик певних макетних об'єктів (наприклад, MockHttpServletRequestвід Springframework).


14
Сподіваюся, ви дотримувались свого святого обов'язку і подавали код на DailyWTF?
кеппла

1
У моїй попередній роботі нам прямо заборонялося надсилати що-небудь з нашої кодової бази до DWTF.
Quant_dev

9
@quant_dev: Те, що вони проводили таку політику, передбачає страшні речі щодо своїх розробників ...
Джон Фішер

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

Просто приймати ярлики насправді недостатньо, щоб отримати лише щодняwtf ...
poolie

9

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

Рішенням цього є початок використання заглушок замість макетів. Стаття, яку я знайшов особливо просвічуючою темою, була знайдена в Javadoc Mockito: http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html (див. "2. Як щодо заглушки?" ), посилаючись на: http://monkeyisland.pl/2008/07/12/should-i-worry-about-the-unexpected/ .

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

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

xUnit Шаблони

Мистецтво одиничного тестування: із прикладами в .Net

Тестування Java наступного покоління: TestNG та розширені концепції (ця книга в основному стосується testNG, але є приємна глава про глузування)


+1 для точки про перевірку виклику надмірних методів. Однак завжди є зворотний бік монети, коли несподіване виклик методу викликає збій у вашому методі. На щастя, Mockito має Answer.RETURNS_SMART_NULLSналаштування для глузування, що допомагає діагностувати це.
Bringer128

4

У своєму досвіді я спостерігав небагато анти-моделей.

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

Інакше мій досвід з глузуванням, особливо Mockito, був вітерцем. Вони зробили тести дуже просто писати та підтримувати. Тестування взаємодії перегляду GWT / презентаторів набагато простіше з макетами, ніж GWTTestCase.


2 і 3 - це певні проблеми! У вас є простий приклад (1)?
Арман

2

Я вважаю, що тести, які використовують макети в декількох шарах програми, особливо важко розшифрувати та змінити. Однак я думаю, що це було пом’якшено в останні роки вдосконаленими API макетів (я використовую JMock там, де це зручно).

5 або 6 років тому API, як EasyMock, були потужними, але дуже громіздкими. Часто код тесту, який використовував його, був на порядок складнішим, ніж код, який він тестував. Тоді я намагався впливати на команди, в яких я працював, дуже економно використовувати це і робити з простими макетами ручної роботи, які були просто альтернативними реалізаціями інтерфейсів спеціально для тестування.

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

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