Nice programing

모의 메서드가 전달 된 인수를 반환하도록 만들기

nicepro 2020. 10. 2. 23:14
반응형

모의 메서드가 전달 된 인수를 반환하도록 만들기


다음과 같은 메소드 서명을 고려하십시오.

public String myFunction(String abc);

Mockito가 메서드가받은 동일한 문자열을 반환하도록 도울 수 있습니까?


Mockito에서 답변을 생성 할 수 있습니다. myFunction 메서드가있는 Application이라는 인터페이스가 있다고 가정 해 보겠습니다.

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

Mockito 답변이있는 테스트 방법은 다음과 같습니다.

public void testMyFunction() throws Exception {
  Application mock = mock(Application.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 1.9.5 및 Java 8부터 람다 함수를 사용하는 더 쉬운 방법이 있습니다.

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


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()방법은 정적 인 AdditionalAnswersMockito 1.9.5에 새로운 클래스; 따라서 올바른 정적 가져 오기가 필요합니다.


Java 8을 사용하면 이전 버전의 Mockito에서도 한 줄로 된 답변을 만들 수 있습니다.

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

물론 이것은 AdditionalAnswersDavid Wallace가 제안한 것만 큼 ​​유용 하지는 않지만 "즉석에서"인수를 변환하려는 경우 유용 할 수 있습니다.


나는 매우 비슷한 문제가 있었다. 목표는 객체를 유지하고 이름으로 반환 할 수있는 서비스를 모의하는 것이 었습니다. 서비스는 다음과 같습니다.

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>();

// mock for method 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));

// mock for method 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"));

Java 8을 사용하면 Steve의 대답

public void testMyFunction() throws Exception {
    Application mock = mock(Application.class);
    when(mock.myFunction(anyString())).thenAnswer(
    invocation -> {
        Object[] args = invocation.getArguments();
        return args[0];
    });

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

편집 : 더 짧게 :

public void testMyFunction() throws Exception {
    Application mock = mock(Application.class);
    when(mock.myFunction(anyString())).thenAnswer(
        invocation -> invocation.getArgument(0));

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

나는 비슷한 것을 사용합니다 (기본적으로 동일한 접근 방식입니다). 때때로 모의 객체가 특정 입력에 대해 미리 정의 된 출력을 반환하도록하는 것이 유용합니다. 다음과 같이 진행됩니다.

private Hashtable<InputObject,  OutputObject> table = new Hashtable<InputObject, OutputObject>();
table.put(input1, ouput1);
table.put(input2, ouput2);

...

when(mockObject.method(any(InputObject.class))).thenAnswer(
       new Answer<OutputObject>()
       {
           @Override
           public OutputObject answer(final InvocationOnMock invocation) throws Throwable
           {
               InputObject input = (InputObject) invocation.getArguments()[0];
               if (table.containsKey(input))
               {
                   return table.get(input);
               }
               else
               {
                   return null; // alternatively, you could throw an exception
               }
           }
       }
       );

This is a pretty old question but i think still relevant. Also the accepted answer works only for String. Meanwhile there is Mockito 2.1 and some imports have changed, so i would like to share my current answer:

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

@Mock
private MyClass myClass;

// this will return anything you pass, but it's pretty unrealistic
when(myClass.myFunction(any())).then(returnsFirstArg());
// it is more "life-like" to accept only the right type
when(myClass.myFunction(any(ClassOfArgument.class))).then(returnsFirstArg());

The myClass.myFunction would look like:

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

You might want to use verify() in combination with the ArgumentCaptor to assure execution in the test and the ArgumentCaptor to evaluate the arguments:

ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
verify(mock).myFunction(argument.capture());
assertEquals("the expected value here", argument.getValue());

The argument's value is obviously accessible via the argument.getValue() for further manipulation / checking /whatever.

참고URL : https://stackoverflow.com/questions/2684630/making-a-mocked-method-return-an-argument-that-was-passed-to-it

반응형