
Mockito๋?
- ๋จ์ ํ
์คํธ๋ฅผ ์ํ Java mocking framework์
๋๋ค.
How to install? ๐ง
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
How to use? ๐ฎ
mock(), @Mock, @InjectMocks
- @Mock
- mock ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ๋ฐํํฉ๋๋ค.
- @InjectMocks
- @Mock์ด๋ @Spy ๊ฐ์ฒด๋ฅผ ์์ ์ ๋ฉค๋ฒ ํด๋์ค์ ์ผ์นํ๋ฉด ์ฃผ์
์ํต๋๋ค.
// static์ผ๋ก import๋ฅผ ํ๊ฒ ๋๋ฉด ์กฐ๊ธ ๋ ๊นจ๋ํ๊ฒ ๋ณผ ์ ์์ต๋๋ค.
import static org.mockito.Mockito.*;
// mock ์ฒ๋ฆฌ๋ฅผ ํฉ๋๋ค.
// Annotation, mock() Method ๊ฐ์ ํํ์
๋๋ค.
@Mock
List annotationMockedList
List mockedList = mock(List.class);
//using mock object
mockedList.add("one");
mockedList.clear();
//๊ฒ์ฆ - ์ฑ๊ณต
verify(mockedList).add("one"); // add("one")๊ฐ ํธ์ถ๋์๋์ง ๊ฒ์ฆํฉ๋๋ค.
verify(mockedList).clear(); // clear()๊ฐ ํธ์ถ๋์๋์ง ๊ฒ์ฆํฉ๋๋ค.
//๊ฒ์ฆ - ์คํจ
verify(mockedList).add("two"); // add("two")์ด ํธ์ถ์ด ๋์ง ์์๊ธฐ์ ์คํจํฉ๋๋ค.
stubbing
// ๊ตฌ์ฒด์ ์ธ ํด๋์ค๋ฅผ mock ์ฒ๋ฆฌํฉ๋๋ค.
LinkedList mockedList = mock(LinkedList.class);
//stubbing
when(mockedList.get(0)).thenReturn("first"); // get(0)์ด ํธ์ถ๋๋ฉด "first"๋ฅผ ๋ฐํํฉ๋๋ค.
when(mockedList.get(1)).thenThrow(new RuntimeException()); // get(1)์ด ํธ์ถ๋๋ฉด RuntimeException ์๋ฌ๋ฅผ ๋ฐ์ํฉ๋๋ค.
System.out.println(mockedList.get(0)); // "first"
System.out.println(mockedList.get(1)); // RuntimeException()
System.out.println(mockedList.get(999)); // 999์ ๋ํ stub ์ฒ๋ฆฌ๋ฅผ ํ์ง ์์๊ธฐ ๋๋ฌธ์ null๊ฐ์ด return๋ฉ๋๋ค.
๋งค๊ฐ๋ณ์ ๊ฒ์ฆ
// ๋ชจ๋ Integer ํ์
๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ ๊ฒฝ์ฐ "element"๋ฅผ ๋๋ ค์ค๋๋ค.
when(mockedList.get(anyInt())).thenReturn("element");
//์ปค์คํ
Matcher๋ฅผ ์ฌ์ฉํ์ฌ stubingํฉ๋๋ค.
when(mockedList.contains(argThat(isValid()))).thenReturn("element");
// "element"
System.out.println(mockedList.get(999));
// ๊ฒ์ฆ - Integer ํ์
๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ผ๋ฉฐ ํธ์ถ๋์๋์ง ๊ฒ์ฆํฉ๋๋ค.
verify(mockedList).get(anyInt());
// ๊ฒ์ฆ - argument matchers
verify(mockedList).add(argThat(someString -> someString.length() > 5));
// ๊ฐ์ ๊ฒ์ฆํ ๋์๋ eq()๋ก ๊ฐ์ธ์ผ ํธ์ถํด์ผ ํฉ๋๋ค.
verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
// ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ์คํจํ๊ฒ ๋ฉ๋๋ค.
verify(mock).someMethod(anyInt(), anyString(), "third argument");
ํธ์ถํ์, ํธ์ถ์๊ฐ ๊ฒ์ฆ
- times(1)์ ๊ธฐ๋ณธ๊ฐ์
๋๋ค.
//using mock
mockedList.add("once");
mockedList.add("twice");
mockedList.add("twice");
mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");
// ๊ฒ์ฆ ๋ฐฉ๋ฒ์๋ ์๋์ ๊ฐ์ด 2๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once");
// ์๋์ ๊ฐ์ด 2, 3๋ฒ๋ ๊ฒ์ฆ์ด ๊ฐ๋ฅํฉ๋๋ค :D
verify(mockedList, times(2)).add("twice");
verify(mockedList, times(3)).add("three times");
// ํ๋ฒ๋ ํธ์ถ๋์ง ์๋ ๊ฒฝ์ฐ never()๊ฐ์ด ํํํ ์ ์์ต๋๋ค ::= times(0)
verify(mockedList, never()).add("never happened");
// ์ ์ด๋ ํ๋ฒ, ์ ์ด๋ x๋ฒ, ์ต๋ x๋ฒ
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("three times");
verify(mockedList, atMost(5)).add("three times");
// ์๊ฐ์ ๋ํ ๊ฒ์ฆ
verify(mockedList, timeout(100)).add("three times");
// ์๊ฐ & ํ์ ๊ฒ์ฆ
verify(mock, timeout(100).times(2)).someMethod();
verify(mock, timeout(100).atLeast(2)).someMethod();
Stubbing void Method
// mockedList์ clear๋ฅผ ํธ์ถํ์์๋ RunTimeException์ ๋ฐํํ๊ฒ ๋ฉ๋๋ค.
doThrow(new RuntimeException()).when(mockedList).clear();
// RuntimeException
mockedList.clear();
์์์ ๋ํ ๊ฒ์ฆ
List singleMock = mock(List.class);
singleMock.add("was added first");
singleMock.add("was added second");
// ์ค์ ์ํ Case
InOrder inOrder = inOrder(singleMock);
// "was added first"๋ถํฐ ๊ฒ์ฆํ "was added second"๋ฅผ ๊ฒ์ฆํ์ฌ ์์์ ๋ํ ๊ฒ์ฆ์ ์งํํฉ๋๋ค.
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");
์๋ฌด์ผ์ด ์ผ์ด๋์ง ์๋ mock์ ๋ํ ๊ฒ์ฆ
// mockOne๋ง add๋ฅผ ํธ์ถํฉ๋๋ค.
mockOne.add("one");
// ์ผ๋ฐ์ ์ธ ๊ฒ์ฆ์
๋๋ค.
verify(mockOne).add("one");
verify(mockOne, never()).add("two");
// ๋๋จธ์ง mock์ ์๋ฌด ์ผ์ด ๋ฐ์ํ์ง ์์๊ธฐ ๋๋ฌธ์ ๊ทธ ๋ถ๋ถ์ ๋ํ ๊ฒ์ฆ์
๋๋ค.
verifyZeroInteractions(mockTwo, mockThree);
์ฐ์์ ์ธ Stubbing
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException()) // ์ฒซ๋ฒ์งธ Return
.thenReturn("foo"); // ๋๋ฒ์งธ Return
//์ฒซ๋ฒ์งธ call: throws runtime exception:
mock.someMethod("some arg");
//๋๋ฒ์งธ call: "foo"
System.out.println(mock.someMethod("some arg"));
//๊ฐ์ฅ ๋ง์ง๋ง Stubbingํ ๊ฐ์ Return ํฉ๋๋ค.
System.out.println(mock.someMethod("some arg"));
// ํธ์ถํ ์์๋๋ก ๊ฒฐ๊ณผ๊ฐ์ Return ํฉ๋๋ค.
when(mock.someMethod("some arg"))
.thenReturn("one", "two", "three");
Spying, @Spy
- Spy๋ฅผ ํตํด ์ค์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ํ์ํ ๋ถ๋ถ์๋ง mock์ฒ๋ฆฌํ์ฌ ๊ฒ์ฆ์ ์งํํ ์ ์์ต๋๋ค.
List list = new LinkedList();
List spy = spy(list);
// Method์ ๋ํ stubbing
when(spy.size()).thenReturn(100);
// ์ค์ ๊ฐ์ฒด์ Method๋ฅผ ํธ์ถํฉ๋๋ค.
spy.add("one");
spy.add("two");
// "one"
System.out.println(spy.get(0));
// Stubbing๋ Method์ ๊ฒฐ๊ณผ : 100
System.out.println(spy.size());
// Spy์ ์ฃผ์ํ ์ .
List list = new LinkedList();
List spy = spy(list);
// ์ค์ ๊ฐ์ฒด์ ์๋ฌด๊ฒ๋ ์๊ธฐ๋๋ฌธ์ when์ ํธ์ถํ๊ฒ ๋๋ฉด IndexOutofBoundsException์ด ๋ฐ์ํฉ๋๋ค.
when(spy.get(0)).thenReturn("foo");
// ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ doReturn์ผ๋ก stubbing์ ์งํํฉ๋๋ค.
doReturn("foo").when(spy).get(0);
Reference