Mockito - різниця між doReturn () та when ()


198

Наразі я перебуваю в процесі використання Mockito для знущання над об'єктами сервісного рівня у додатку Spring MVC, в якому я хочу перевірити свої методи Controller. Однак, коли я читав про специфіку Mockito, я виявив, що методи doReturn(...).when(...)еквівалентні when(...).thenReturn(...). Отже, моє запитання полягає в тому, який сенс мати два методи, які роблять те саме, або яка тонка різниця між doReturn(...).when(...)і when(...).thenReturn(...)?

Будь-яка допомога буде вдячна.


1
У javadoc є кілька випадків, коли doReturn()це корисно.
— Сотіріос Деліманоліс

5
Я думаю, що одна з головних відмінностей полягає в тому, що doReturn (...). Коли (..) є старшим, і це не такий тип безпеки, і тому ми можемо використовувати його іноді, коли компілятор продовжує скаржитися на кастинг. Коли (..)., То повернути (..) набагато краще з точки зору безпеки типу
— user2511882

Відповіді:


229

Два синтаксису для заглушки приблизно рівнозначні. Однак завжди можна використовувати doReturn/whenдля заглушки; але є випадки, коли ви не можете користуватися when/thenReturn. Методи заглушки порожнечі - одна з таких. Інші включають використання шпигунів Mockito та заглушення одного і того ж методу не один раз.

Одне, що when/thenReturnдає вам, а doReturn/whenце не - це перевірка типу значення, яке ви повертаєте, під час компіляції. Однак я вважаю, що це майже не має значення - якщо ви помилилися з типом, ви дізнаєтесь, як тільки запустите тест.

Настійно рекомендую тільки використовувати doReturn/when. Немає сенсу вивчати два синтаксиси, коли це зробимо.

Ви можете звернутися до моєї відповіді на "Граматиці" Мокіто - більш детальної відповіді на дуже тісне питання.


16
Я якось не згоден з Девідом. Я часто стикаюся з ситуаціями, коли повертаю неправильний тип під час використання doReturn/whenі витрачаю наступні хвилини на з'ясування того, що пішло не так. Перевірка типу компіляції стає надзвичайно корисною для when/thenReturn.
— Сакет

11
Просто майте на увазі, що Mockito рекомендує використовувати when/thenReturnзамість цього doReturn/when.
— CodyEngel

2
@CodyEngel, і немає такої причини для такої рекомендації, окрім того, що я окреслив у своїх відповідях тут і на stackoverflow.com/q/11462697 . Кілька років тому я обговорював це з Брісом Датейлом, який зараз є головним розробником Mockito, і, наскільки я пам’ятаю, він погоджується. Я попрошу його написати тут коментар (немає гарантії, що він це зробить).
— Давуд ібн Карім

18
У Javadoc йдеться , що doReturn/whenпредставляє собою компроміс. Команда не рекомендує так чи інакше, але зауважимо, що when/thenпідхід є більш інтуїтивним, читабельнішим і пропонує перевірити час компіляції, саме такий підхід зробив Mockito популярним і простим у використанні, не забувайте, що коли базу коду поділяють різноманітний набір навичок у вашій команді; але він має недоліки щодо шпигунів та методів недійсності.
— Бріс

5
Як раз для запису: doReturn()має великий недолік перетворення на стиль кодування викликів методу в стилі YODA. Пізніше річ записується спочатку, що є. Більшість людей читають зліва направо; тому вам доведеться постійно пам’ятати, щоб повернути назад логіку в голові.
— GhostCat

200

Обидва підходи поводяться по-різному, якщо ви використовуєте шпигуючий об'єкт (анотований з @Spy) замість макету (анотовано з @Mock):

  • when(...) thenReturn(...) робить справжній виклик методу безпосередньо перед поверненням вказаного значення. Тож якщо виклик методу кидає виняток, вам доведеться зіткнутися з ним / знущатися над ним і т. Д. Звичайно, ви все одно отримаєте результат (що ви визначаєте thenReturn(...))

  • doReturn(...) when(...) метод взагалі не викликає .

Приклад:

public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}

Тест:

@Spy
private MyClass myClass;

// ...

// would work fine
doReturn("test").when(myClass).anotherMethodInClass();

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");

37
Така поведінка просто працює для шпигуючих об'єктів, оскільки є "обгорткою" реальних об'єктів. Що стосується знущаються об’єктів, то не має значення, коли це / тодіПовернення чи доРевертування / Коли. Знущаються об’єкти ніколи не називають реальними методами.
— Рафаель Ораджо

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

@Gleichmut Це був гіпотетичний сценарій, де я показую використання / перевагу doReturn. У реальному застосуванні метод, який просто повертає виняток, звичайно не має сенсу .. але у вас є методи (напевно, не такі тонкі, як цей), які можуть кидати винятки в певних умовах ..
— akcasoy

1
Просто для уточнення: метод When (). ThenReturn () викликає фактичний метод (шпигуна - не має значення для макетів) лише один раз. Це відбувається в рядку, який ви вказуєте макет поведінки (коли ( myClass.anotherMethodInClass () .thenRet ...). Після цього фактичний метод більше ніколи не викликається. Можливо, добре знати, якщо ви очікували певної логіки декоратора, читаючи пояснення вище.
— Йонас

Це не здається перевагою doReturn(), це виглядає як зловживання бібліотекою. Сенс шпигунства замість чистого глузування - скористатися реальними дзвінками. Вони також застерігають від використання таких шпигунів: github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes) (і рекомендують замість цього розширити клас та замінити метод)
— Метью читайте

13

Здається, Mockito javadoc розповідає, чому використовувати doReturn()замість when() Use doReturn () у тих рідкісних випадках, коли ви не можете використовувати Mockito.when (Object).

Слідкуйте за тим, щоб Mockito.when (Object) завжди рекомендувався для заглушки, тому що він є безпечним для аргументів і є легшим для читання (особливо при заглушці послідовних дзвінків).

Ось ті рідкісні випадки, коли doReturn () стане в нагоді:

1. Під час шпигування реальних об'єктів та виклику реальних методів шпигуну приносять побічні ефекти

List list = new LinkedList(); List spy = spy(list);

// Неможливо: реальний метод називається так spy.get (0) викидає IndexOutOfBoundsException (список ще порожній)

when(spy.get(0)).thenReturn("foo");

// Ви повинні використовувати doReturn () для заглушки: doReturn("foo").when(spy).get(0);

2. Переосмислення попереднього виключення:

when(mock.foo()).thenThrow(new RuntimeException());

// Неможливо: метод foo () викликається виключенням, так називається RuntimeException. when(mock.foo()).thenReturn("bar");

// Ви повинні використовувати doReturn () для заглушки:

doReturn("bar").when(mock).foo(); Наведені вище сценарії показують компроміс елегантного синтаксису Мокіто. Зауважте, що сценарії дуже рідкісні. Шпигунство має бути спорадичним, а переважаючий виняток - заїдання дуже рідко. Не кажучи вже про те, що загалом зависаючий заглушок є потенційним кодовим запахом, який вказує на занадто багато задирок.


7

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

PowerMockito.doReturn(false, false, true).when(SomeClass.class, "SomeMethod", Matchers.any(SomeClass.class));

Таким чином, він поверне помилковим, коли метод буде викликаний у тому самому тестовому випадку, і тоді він поверне помилкове знову і остаточно вірно.


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