이 글은 Junit5를 기준으로 작성되었습니다.
0. Mockito란?
가짜 객체인 Mock을 만들어 테스트를 원활하게 도와주는 테스트 프레임워크.
스터빙으로 Mock을 조작합니다.
💡 스터빙(Stubbing) : Mock 객체의 행동을 조작하여 원하는 결과를 반환하도록 하는 행위
1. Mock 학습 테스트
1.1 mock
mock을 이용해 Mock 객체를 만들 수 있습니다.
import static org.mockito.Mockito.*;
List<String> mocks = mock(ArrayList.class);
💡 mock은 가짜 객체이므로, mock을 통해 만들어진 객체의 메소드는 동작하지 않습니다.
1.2 when
when을 사용해 행동에서, thenReturn을 사용해 값을 리턴하도록 만들 수 있습니다.
이를 스터빙이라 합니다.
아래 코드는 get(0)를 호출하면, ksb를 반환하라는 의미입니다.
@Test
public void whenThenReturnTest(){
List<String> mocks = mock(ArrayList.class);
String givenValue = mocks.get(0);
when(givenValue).thenReturn("ksb");
assertEquals("ksb", mocks.get(0));
}
예외 처리가 필요할 경우에, when-thenThrow로 해결할 수 있습니다.
@Test
public void whenThenThrowTest(){
List<String> mocks = mock(ArrayList.class);
mocks.add(null);
when(mocks.get(0))
.thenThrow(NullPointerException.class);
}
1.3 any
일정한 반환 값을 인자와 무관하게 만들고 싶을 때 사용합니다.
anyInt(), anyString(), anyLong() 등이 있습니다.
@Test
public void anyTest(){
List<String> mocks = mock(ArrayList.class);
String givenValue = mocks.get(anyInt());
when(givenValue).thenReturn("ksb");
assertEquals("ksb", mocks.get(0));
assertEquals("ksb", mocks.get(1));
assertEquals("ksb", mocks.get(10_000_000));
}
1.4 verify
mock 객체에서 어떤 메소드가 호출되었는지 알고 싶을 때 사용합니다.
아래 코드로 List Mock 객체에서 add()가 호출 되었다는 것을 검증합니다.
@Test
public void verifyTest(){
List<String> mocks = mock(ArrayList.class);
mocks.add("ksb");
verify(mocks).add("ksb");
}
1.5 times
mock 개체에서 메소드가 몇 번 호출되었는지 확인할 때 사용합니다.
아래 코드로 add()가 두 번 호출된 것을 검증합니다.
@Test
public void verifyTimeTest(){
List<String> mocks = mock(ArrayList.class);
mocks.add("ksb");
mocks.add("ksb2");
verify(mocks, times(2)).add(anyString());
}
atLeast(), atLeastOnce()로 최소로 호출되는 횟수를 검증할 수 있습니다.
@Test
public void verifyAtLeastAndAtLeastOnceTest(){
List<String> mocks = mock(ArrayList.class);
mocks.add("ksb");
mocks.add("ksb2");
mocks.add("ksb3");
mocks.add("ksb4");
verify(mocks, atLeast(2)).add(anyString());
verify(mocks, atLeastOnce()).add(anyString());
}
1.6 argumentCaptor
mock 객체에 전달된 인자를 확인할 때 사용합니다.
verify()에 capture()를 전달하고, getValue()로 전달된 인자를 확인할 수 있습니다.
@Test
public void argumentCaptorTest(){
List<String> mocks = mock(ArrayList.class);
ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class);
mocks.add("ksb");
verify(mocks).add(arg.capture());
assertEquals("ksb", arg.getValue());
}
2. Spy 학습 테스트
2.1 spy
spy를 통해 만들어진 객체는 실제 객체처럼 동작합니다.
즉, mock과 달리 내부 메소드가 동작됩니다.
@Test
public void spyingEqualTest(){
List<String> spies = spy(ArrayList.class);
spies.add("ksb");
assertEquals("ksb", spies.get(0));
}
2.2 verify
mock과 동일하게 verify로 호출된 메소드를 검증할 수 있습니다.
@Test
public void spyingVerifyTest(){
List<String> spies = spy(ArrayList.class);
spies.add("ksb");
verify(spies).add("ksb");
spies.get(0);
verify(spies).get(0);
}
2.3 exception
spy는 mock과 달리 실제 메소드가 동작됩니다.
@Test
public void spyingIndexOutOfBoundsExceptionTest(){
List<String> spies = spy(ArrayList.class);
assertThrows(IndexOutOfBoundsException.class, () -> {
when(spies.get(0)).thenReturn("ksb");
});
}
때문에, 위 코드에서 spies.get(0)는 내부에 아무런 값이 저장되어 있지 않아 IndexOutOfBoundsException가 발생합니다.
2.4 doReturn-when
2.3에서 발생하는 spy 함수 호출 문제를 doReturn-when으로 해결할 수 있습니다.
@Test
public void spyingDoReturnTest(){
List<String> spies = spy(ArrayList.class);
doReturn("ksb").when(spies).get(0);
doReturn("ksb1").when(spies).get(1);
assertEquals("ksb", spies.get(0));
assertEquals("ksb1", spies.get(1));
}