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.

Комментарии (14)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Мая Уровень 82
14 октября 2025
а почему мы в методе invocation.getArgument(0) подставляем 0, когда у нас не 0, а 10 и 5?
Ardan Уровень 57
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(объект).имяМетода(параметр);
Nikita Shamrai Уровень 8 Expert
25 июля 2022
getArgument - это метод с рефлексии?