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.