9

"Как сделать так, чтобы имитируемый метод возвращал аргумент, который был ему передан?"

5

Проблема:

У меня есть метод с таким сигнатурой:

public String myFunction(String abc);

Мне нужно, чтобы Mockito возвращал ту же строку, которую метод получает в качестве аргумента. Может ли Mockito помочь в этом? Если да, то как правильно настроить моки для достижения этого результата?

5 ответ(ов)

14

Начиная с Mockito 1.9.5+ и Java 8+

Вы можете использовать лямбда-выражение следующим образом:

when(myMock.myFunction(anyString())).thenAnswer(i -> i.getArguments()[0]);

Где i является экземпляром InvocationOnMock.

Для более старых версий

Вы можете создать ответ (Answer) в Mockito. Допустим, у нас есть интерфейс с названием MyInterface, содержащий метод myFunction.

public interface MyInterface {
    public String myFunction(String abc);
}

Вот пример тестового метода с использованием ответа Mockito:

public void testMyFunction() throws Exception {
    MyInterface mock = mock(MyInterface.class);
    when(mock.myFunction(anyString())).thenAnswer(new Answer<String>() {
        @Override
        public String answer(InvocationOnMock invocation) throws Throwable {
            Object[] args = invocation.getArguments();
            return (String) args[0];
        }
    });

    assertEquals("someString", mock.myFunction("someString"));
    assertEquals("anotherString", mock.myFunction("anotherString"));
}

Таким образом, вы можете адаптировать своё использование Mockito в зависимости от версии библиотеки и языка.

7

Если у вас есть Mockito версии 1.9.5 или выше, то появился новый статический метод, который может автоматически создавать объект Answer для вас. Вам нужно написать что-то вроде:

import static org.mockito.Mockito.when;
import static org.mockito.AdditionalAnswers.returnsFirstArg;

when(myMock.myFunction(anyString())).then(returnsFirstArg());

или альтернативно:

doAnswer(returnsFirstArg()).when(myMock).myFunction(anyString());

Обратите внимание, что метод returnsFirstArg() является статическим в классе AdditionalAnswers, который появился в Mockito начиная с версии 1.9.5. Поэтому убедитесь, что вы добавили правильный статический импорт.

1

С Java 8 это возможно сделать в одну строку, даже с более старыми версиями Mockito:

when(myMock.myFunction(anyString())).then(i -> i.getArgumentAt(0, String.class));

Конечно, это не так полезно, как использование AdditionalAnswers, предложенное Дэвидом Уоллесом, но может оказаться полезным, если вам нужно преобразовать аргумент "на лету".

0

У меня была очень похожая проблема. Цель заключалась в том, чтобы создать мок-сервис, который сохраняет объекты и может возвращать их по имени. Сервис выглядит следующим образом:

public class RoomService {
    public Room findByName(String roomName) {...}
    public void persist(Room room) {...}
}

Мок-сервис использует карту для хранения экземпляров Room.

RoomService roomService = mock(RoomService.class);
final Map<String, Room> roomMap = new HashMap<String, Room>();

// мок для метода persist
doAnswer(new Answer<Void>() {
    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        Object[] arguments = invocation.getArguments();
        if (arguments != null && arguments.length > 0 && arguments[0] != null) {
            Room room = (Room) arguments[0];
            roomMap.put(room.getName(), room);
        }
        return null;
    }
}).when(roomService).persist(any(Room.class));

// мок для метода findByName
when(roomService.findByName(anyString())).thenAnswer(new Answer<Room>() {
    @Override
    public Room answer(InvocationOnMock invocation) throws Throwable {
        Object[] arguments = invocation.getArguments();
        if (arguments != null && arguments.length > 0 && arguments[0] != null) {
            String key = (String) arguments[0];
            if (roomMap.containsKey(key)) {
                return roomMap.get(key);
            }
        }
        return null;
    }
});

Теперь мы можем запускать наши тесты на этом моке. Например:

String name = "room";
Room room = new Room(name);
roomService.persist(room);
assertThat(roomService.findByName(name), equalTo(room));
assertNull(roomService.findByName("none"));

Таким образом, мы создали простую и эффективную имитацию сервиса, которая позволяет нам проверять функциональность сохранения и поиска объектов Room.

0

Эта вопрос уже довольно старый, но, думаю, все еще актуален. При этом, принятый ответ работает только со строками. Учитывая, что есть Mockito 2.1 и некоторые импорты изменились, хотел бы поделиться своим текущим решением:

import static org.mockito.AdditionalAnswers.returnsFirstArg;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@Mock
private MyClass myClass;

// это будет возвращать всё, что вы передаете, но это довольно нереалистично
when(myClass.myFunction(any())).then(returnsFirstArg());
// более "жизненно" будет принимать только нужный тип
when(myClass.myFunction(any(ClassOfArgument.class))).then(returnsFirstArg());

Метод myClass.myFunction будет выглядеть так:

public class MyClass {
    public ClassOfArgument myFunction(ClassOfArgument argument){
        return argument;
    }  
}

Надеюсь, это поможет!

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь