Mockito: doAnswer Vs thenReturn


124

Я використовую Mockito для подальшого тестування блоку обслуговування. Я збентежений , коли використовувати doAnswerпроти thenReturn.

Хтось може мені детально допомогти? Поки я спробував це thenReturn.

Відповіді:


167

Ви повинні використовувати thenReturnабо doReturnколи ви знаєте, що повертається значення під час знущання над викликом методу. Це визначене значення повертається, коли ви викликаєте знуджений метод.

thenReturn(T value) Встановлює значення повернення, яке потрібно повернути, коли викликається метод.

@Test
public void test_return() throws Exception {
    Dummy dummy = mock(Dummy.class);
    int returnValue = 5;

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenReturn(returnValue);
    doReturn(returnValue).when(dummy).stringLength("dummy");
}

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

Використовуйте, doAnswer()коли ви хочете заглушити недійсний метод із загальним Answer.

Відповідь вказує на дію, яка виконується, і повернене значення, яке повертається під час взаємодії з макетом.

@Test
public void test_answer() throws Exception {
    Dummy dummy = mock(Dummy.class);
    Answer<Integer> answer = new Answer<Integer>() {
        public Integer answer(InvocationOnMock invocation) throws Throwable {
            String string = invocation.getArgumentAt(0, String.class);
            return string.length() * 2;
        }
    };

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenAnswer(answer);
    doAnswer(answer).when(dummy).stringLength("dummy");
}

привіт @ Roland Weisleder, але іноді ви повинні повернути деякий створений значення внутрішній код і нічого спільного з аргументами, наприклад code = UUID.randomUUID(), я виявив неможливим це реалізувати mockito.
zhuguowei

3
Коли ваш макет повинен повернути новий UUID для кожної виклику, з якою ви будете реалізовувати Answerjust з return UUID.randomUUID();.
Roland Weisleder

Чи можу я взяти цей метод з нового мурашника ініціалізації відповіді, щоб він став у якийсь метод, щоб зробити код трохи більш чистим?
Рядок

3
@Line Answer- це функціональний інтерфейс, тому з Java 8 ви можете замінити його на лямбда-вираз. Якщо це недостатньо чисто, можливе будь-яке інше звичне та незвичне рефакторинг.
Roland Weisleder

@ zhuguowei: повернути якесь значення, створене внутрішнім кодом? Що ти маєш на увазі?
Саурабх Патіл

34

doAnswerі thenReturnте ж саме, якщо:

  1. Ви використовуєте Mock, а не Spy
  2. Метод, який ви заглушуєте, повертає значення, а не недійсний метод.

Давайте знущаємось із цієї BookService

public interface BookService {
    String getAuthor();
    void queryBookTitle(BookServiceCallback callback);
}

Ви можете заглушити getAuthor () за допомогою doAnswerта thenReturn.

BookService service = mock(BookService.class);
when(service.getAuthor()).thenReturn("Joshua");
// or..
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        return "Joshua";
    }
}).when(service).getAuthor();

Зауважте, що під час використання doAnswerви не можете передати метод when.

// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());

Отже, коли б ви використовували doAnswerзамість цього thenReturn? Я можу придумати два випадки використання:

  1. Коли ви хочете "заглушити" недійсний метод.

Використовуючи doAnswer, ви можете зробити деякі додаткові дії після виклику методу. Наприклад, запустіть зворотний виклик у queryBookTitle.

BookServiceCallback callback = new BookServiceCallback() {
    @Override
    public void onSuccess(String bookTitle) {
        assertEquals("Effective Java", bookTitle);
    }
};
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        BookServiceCallback callback = (BookServiceCallback) invocation.getArguments()[0];
        callback.onSuccess("Effective Java");
        // return null because queryBookTitle is void
        return null;
    }
}).when(service).queryBookTitle(callback);
service.queryBookTitle(callback);
  1. Коли ви використовуєте Spy замість Mock

При використанні When-thenReturn на Spy Mockito зателефонує реальним методом та заглушить вашу відповідь. Це може спричинити проблеми, якщо ви не хочете викликати реальний метод, як у цьому зразку:

List list = new LinkedList();
List spy = spy(list);
// Will throw java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
when(spy.get(0)).thenReturn("java");
assertEquals("java", spy.get(0));

Використовуючи doAnswer, ми можемо сміливо заглушити це.

List list = new LinkedList();
List spy = spy(list);
doAnswer(invocation -> "java").when(spy).get(0);
assertEquals("java", spy.get(0));

Насправді, якщо ви не бажаєте робити додаткових дій при виклику методу, ви можете просто скористатися doReturn.

List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));

що робити, якщо глузливий метод недійсний?
Ігор Донін

1
Ігоре, саме там doAnswer () потрапляє до картини, і він це висвітлив у відповіді вище.
Саурабх Патіл

Під час використання doAnswer(new Answer() { ... return null;}я отримую попередження у затемненні для "Відповідь - це необроблений тип. Посилання на загальний тип Відповідь <T> слід параметризувати". Чи є спосіб вирішити це питання (крім ігнорування попередження ofc)?
LazR
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.