JavaRush /Курсы /JSP & Servlets /Вызовы mock-методов с параметрами

Вызовы mock-методов с параметрами

JSP & Servlets
4 уровень , 3 лекция
Открыта

4.1 Параметры методов

Предыдущие правила добавленные мок-объекту касались методов без параметров. А как создавать правила для методов с параметрами? Более того, хотелось бы создавать правила, чтобы при одних значениях параметров был один результат, а при других – другой.

Так тоже можно делать. Если вы хотите, чтобы при определенном параметре метод возвращал что-то определенное, то правило можно записать так:

Mockito.doReturn(результат).when(объект).имяМетода(параметр);

И сразу рассмотрим пример, чтобы лучше все понять. Пусть наш List возвращает имя Иван при запросе 10-го элемента, и имя Марья при запросе 500-го. Сказано – сделано.


@ExtendWith(MockitoExtension.class)
class ParamsTest {
 @Mock
 List mockList;
 
 @Test
    public void whenMockAnnotation() {
        //добавление первого правила
        Mockito.doReturn("Иван").when(mockList).get(10);       
        //добавление второго правила
        Mockito.doReturn("Марья").when(mockList).get(500);  
 
        assertEquals("Иван", mockList.get(10)); 
        assertEquals("Марья", mockList.get(500)); 
 
    }
}

4.2 Шаблоны параметров

И сразу хитрые коллеги зададут мне вопрос: “А как быть, если метод требует аргументы, но при любых значениях должен возвращать один и тот же результат?”. Не будем же мы писать:


Mockito.doReturn("Иван").when(mockList).get(1);  
Mockito.doReturn("Иван").when(mockList).get(2); 
Mockito.doReturn("Иван").when(mockList).get(99);   

Нет, никто тебя так писать не заставляет. Если ты хочешь добавить правило mock-объекту, которое действует для метода с любыми аргументами, то для этого есть специальный объект:

Mockito.any()

Наш пример с его помощью будет записан так:

Mockito.doReturn("Иван").when(mockList).get(any(int.class));

Есть тут пара нюансов. Объект Mockito.any() имеет тип Object, поэтому для параметров разных типов есть его аналоги:

Метод Тип параметра
1 any() Object, включая null
2 any(ClassName.class) ClassName
3 anyInt() int
4 anyBoolean() boolean
5 anyDouble() double
6 anyList() List

Более корректно наш пример будет выглядеть так:

Mockito.doReturn("Иван").when(mockList).get(anyInt());

4.3 Метод doAnswer()

Мы добрались до сложного поведения виртуальных методов. Рано или поздно наступит ситуация, когда ты захочешь, чтобы этот виртуальный метод имел сложное поведение. Например, он должен возвращать значения в зависимости от параметров, преобразовывать строку в верхний регистр.

Для этого есть специальный метод – doAnswer(), в который передается функция, которая делает то, что тебе нужно:

Mockito.doAnswer(функция).when(объект).имяМетода(параметр);

Давай заставим метод get() класса List возвращать квадрат переданного ему аргумента. И напишем такую программу:


@ExtendWith(MockitoExtension.class)
class DoAnswerTest {
 @Mock
 List mockList;
 
 @Test
    public void whenMockAnnotation() {
        Mockito.doAnswer(invocation -> {
            int parameter = invocation.getArgument(0);
            return parameter * parameter;
        }).when(mockList).get(anyInt());   
 
        assertEquals(100, mockList.get(10)); 
        assertEquals(25, mockList.get(5)); 
    }
}

Функцию мы задали с помощью объект класса Answer.

Комментарии (16)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Underdante Уровень 62
10 августа 2026
а если тестируемый метод возвращает воид?
Мая Уровень 82
14 октября 2025
а почему мы в методе invocation.getArgument(0) подставляем 0, когда у нас не 0, а 10 и 5?
9 августа 2026
getArgument(0) это возврат первого аргумента метода значит
rwnmei Уровень 38
28 августа 2025
Прикольно все понятно
Артем Уровень 71
13 февраля 2025
Мы добрались до сложного поведения виртуальных методов. Теперь пора писать тесты на тесты😁
Арсений Уровень 65
23 декабря 2023
Павел Уровень 19 Expert
18 декабря 2023
Не понял в лекции: int.class это mock на примитивный тип данных int?
Олег Уровень 79 Expert
3 декабря 2023
И сразу рассмотрим пример, чтобы лучше все понять. Пусть наш List возвращает имя Иван при запросе 10-го элемента, и имя Марья при запросе 500-го. Сказано – сделано. Такие тесты работает как наша экономика с экрана ТВ. Намолотили, выпустили, прирост ВВП на душу населения, какую задачу поставили, то в эфир вылили, а какая истинная картина пофиг..... Так и эти тесты... Там может всё на перекосяк пошло, а они показывают всё Ок!!! Искусственные они какие то...
11 июля 2024
так моки про искусвенность и есть, это в самом начале говорится. Предположим у вас есть серверная часть отдельно и клиентская отдельно, тестируем клиентскую, сервер должен что то возвращать для того чтобы тестируемый метод отрабатывал как надо, и вот класс-коннектор к серверу как раз и мокается, чтобы что то возвращал ожидаемое от сервера, а не дергать сервер каждый раз, тем более его может и не быть
Redya Daniel Уровень 16
25 февраля 2023
Не понял этого момента. Какого типа у нас invocation?

Mockito.doAnswer(invocation -> {
            int parameter = invocation.getArgument(0);
            return parameter * parameter;
        }).when(mockList).get(anyInt());

jvatechs Уровень 111 Expert
16 мая 2023
Я так понял это лямбда-выражение исходит из переопределения метода answer(InvocationOnMock invocation) интерфейса Answer, т.е. создается анонимный класс. По-иному это можно переписать так:

Mockito.doAnswer(new Answer<Integer>() {
    @Override
    public Integer answer(InvocationOnMock invocation) {
        int parameter = invocation.getArgument(0);
        return parameter * parameter;
    }
}).when(mockList).get(anyInt());
про InvocationOnMock invocation нашел следующее: При использовании Mockito InvocationOnMockобъект автоматически создается фреймворком при вызове фиктивного метода. Он представляет собой вызов метода и содержит такую ​​информацию, как аргументы метода, фиктивный объект и другие сведения. В предоставленном фрагменте кода invocationOnMockэто имя, данное автоматически созданному InvocationOnMockобъекту в answer()методе. Он не создается вами, а скорее передается в качестве параметра метода фреймворком Mockito при вызове фиктивного метода. Таким образом, несмотря на то, что InvocationOnMockэто интерфейс, вы все равно можете получить доступ к его методам и свойствам через автоматически созданный объект, предоставляемый инфраструктурой Mockito.
Anonymous #1384518 Уровень 35 Expert
3 августа 2023
В Intellij есть удобная фишка. Можно после нужного вызова метода или переменной поставить .var далее tab и он сгенерирует результат в переменную с типом. Очень помогает в стримах, где непонятно какой тип возвращается. После просмотра, можно вернуть назад ctrl+z
Сергей Уровень 111 Expert
1 октября 2022
Вместо

Mockito.doReturn("Иван").when(mockList.get(any(int.class)));
Mockito.doReturn("Иван").when(mockList.get(anyInt());
Нужно писать так:

Mockito.doReturn("Иван").when(mockList).get(any(int.class));
Mockito.doReturn("Иван").when(mockList).get(anyInt());
Иначе будет:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at MockitoTest.doReturnStringListWhenAnySizeList(MockitoTest.java:101)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, which is not supported
 3. you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
Stas S Уровень 108 Expert
8 сентября 2022
Оба примера упадут с UnfinishedStubbingException и не потому, что там не хватает круглой скобки :) Правильно писать так :

Mockito.doAnswer(функция).when(объект).имяМетода(параметр);