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