1. 개요
이 예제에서는 Mockito 라이브러리의 @Mock , @Spy , @Captor 및 @InjectMocks 어노테이션을 다룹니다 .
더 많은 Mockito 장점을 보려면 여기에서 시리즈를 살펴보십시오 .
2. Mockito 어노테이션 활성화
더 진행하기 전에 Mockito 테스트에서 어노테이션을 사용할 수 있는 다양한 방법을 살펴보겠습니다.
2.1. MockitoJUnitRunner
첫 번째 옵션은 MockitoJUnitRunner 로 JUnit 테스트에 어노테이션 을 추가하는 것입니다 .
@RunWith(MockitoJUnitRunner.class)
public class MockitoAnnotationTest {
...
}
2.2. MockitoAnnotations.openMocks()
또는 MockitoAnnotations.openMocks() 를 호출하여 프로그래밍 방식으로 Mockito 어노테이션을 활성화 할 수 있습니다 .
@Before
public void init() {
MockitoAnnotations.openMocks(this);
}
2.3. MockitoJUnit.rule()
마지막으로 MockitoJUnit.rule() 을 사용할 수 있습니다 .
public class MockitoInitWithMockitoJUnitRuleUnitTest {
@Rule
public MockitoRule initRule = MockitoJUnit.rule();
...
}
이 경우 규칙을 공개 해야 합니다 .
3. @Mock 어노테이션
Mockito에서 가장 널리 사용되는 어노테이션은 @Mock 입니다. Mockito.mock 을 수동으로 호출하지 않고도 @Mock 을 사용 하여 모의 인스턴스를 생성하고 주입할 수 있습니다.
다음 예제에서는 @Mock 어노테이션 을 사용하지 않고 조롱된 ArrayList 를 수동으로 생성합니다.
@Test
public void whenNotUseMockAnnotation_thenCorrect() {
List mockList = Mockito.mock(ArrayList.class);
mockList.add("one");
Mockito.verify(mockList).add("one");
assertEquals(0, mockList.size());
Mockito.when(mockList.size()).thenReturn(100);
assertEquals(100, mockList.size());
}
이제 동일한 작업을 수행하지만 @Mock 어노테이션을 사용하여 모의를 주입합니다.
@Mock
List<String> mockedList;
@Test
public void whenUseMockAnnotation_thenMockIsInjected() {
mockedList.add("one");
Mockito.verify(mockedList).add("one");
assertEquals(0, mockedList.size());
Mockito.when(mockedList.size()).thenReturn(100);
assertEquals(100, mockedList.size());
}
두 예에서 모의가 올바르게 작동하는지 확인하기 위해 모의와 상호 작용하고 이러한 상호 작용 중 일부를 확인하는 방법에 유의하십시오.
4. @Spy 어노테이션
이제 @Spy 어노테이션을 사용하여 기존 인스턴스를 감시하는 방법을 살펴보겠습니다.
다음 예에서는 @Spy 어노테이션 을 사용하지 않고 List 의 스파이를 만듭니다.
@Test
public void whenNotUseSpyAnnotation_thenCorrect() {
List<String> spyList = Mockito.spy(new ArrayList<String>());
spyList.add("one");
spyList.add("two");
Mockito.verify(spyList).add("one");
Mockito.verify(spyList).add("two");
assertEquals(2, spyList.size());
Mockito.doReturn(100).when(spyList).size();
assertEquals(100, spyList.size());
}
이제 동일한 작업을 수행하여 List을 spy하지만 @Spy 어노테이션을 사용합니다.
@Spy
List<String> spiedList = new ArrayList<String>();
@Test
public void whenUseSpyAnnotation_thenSpyIsInjectedCorrectly() {
spiedList.add("one");
spiedList.add("two");
Mockito.verify(spiedList).add("one");
Mockito.verify(spiedList).add("two");
assertEquals(2, spiedList.size());
Mockito.doReturn(100).when(spiedList).size();
assertEquals(100, spiedList.size());
}
이전과 마찬가지로 여기에서 스파이와 상호 작용하여 스파이가 올바르게 작동하는지 확인합니다. 이 예에서 우리는:
- 실제 메서드 spiedList.add() 를 사용하여 spiedList 에 요소를 추가 했습니다 .
- Mockito.doReturn () 을 사용하여 2 대신 100 을 반환하도록 spiedList.size() 메서드 를 스터 빙 했습니다.
5. @Captor 어노테이션
다음으로 @Captor 어노테이션을 사용하여 ArgumentCaptor 인스턴스를 만드는 방법을 살펴보겠습니다.
다음 예제에서는 @Captor 어노테이션 을 사용하지 않고 ArgumentCaptor 를 만듭니다.
@Test
public void whenNotUseCaptorAnnotation_thenCorrect() {
List mockList = Mockito.mock(List.class);
ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class);
mockList.add("one");
Mockito.verify(mockList).add(arg.capture());
assertEquals("one", arg.getValue());
}
이제 같은 목적 으로 @Captor 를 사용하여 ArgumentCaptor 인스턴스를 생성해 보겠습니다.
@Mock
List mockedList;
@Captor
ArgumentCaptor argCaptor;
@Test
public void whenUseCaptorAnnotation_thenTheSame() {
mockedList.add("one");
Mockito.verify(mockedList).add(argCaptor.capture());
assertEquals("one", argCaptor.getValue());
}
구성 로직을 제거할 때 테스트가 어떻게 더 간단해지고 더 읽기 쉬워지는지 주목하십시오.
6. @InjectMocks 어노테이션
이제 @InjectMocks 어노테이션을 사용하여 모의 필드를 테스트된 객체에 자동으로 삽입하는 방법에 대해 논의해 보겠습니다.
다음 예제에서는 @InjectMocks 를 사용하여 모의 wordMap 을 MyDictionary dic 에 삽입합니다 .
@Mock
Map<String, String> wordMap;
@InjectMocks
MyDictionary dic = new MyDictionary();
@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");
assertEquals("aMeaning", dic.getMeaning("aWord"));
}
다음은 MyDictionary 클래스입니다 .
public class MyDictionary {
Map<String, String> wordMap;
public MyDictionary() {
wordMap = new HashMap<String, String>();
}
public void add(final String word, final String meaning) {
wordMap.put(word, meaning);
}
public String getMeaning(final String word) {
return wordMap.get(word);
}
}
7. 스파이에게 모의 주입하기
위의 테스트와 유사하게 우리는 스파이에 mock을 주입하고 싶을 수 있습니다:
@Mock
Map<String, String> wordMap;
@Spy
MyDictionary spyDic = new MyDictionary();
그러나 Mockito는 스파이에 모의 주입을 지원하지 않으며 다음 테스트 결과 예외가 발생합니다.
@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");
assertEquals("aMeaning", spyDic.getMeaning("aWord"));
}
스파이와 함께 모의를 사용하려면 생성자를 통해 모의를 수동으로 주입할 수 있습니다.
MyDictionary(Map<String, String> wordMap) {
this.wordMap = wordMap;
}
어노테이션을 사용하는 대신 이제 수동으로 스파이를 만들 수 있습니다.
@Mock
Map<String, String> wordMap;
MyDictionary spyDic;
@Before
public void init() {
MockitoAnnotations.openMocks(this);
spyDic = Mockito.spy(new MyDictionary(wordMap));
}
이제 테스트가 통과됩니다.
8. 어노테이션을 사용하는 동안 NPE 실행
@Mock 또는 @Spy 어노테이션이 달린 인스턴스를 실제로 사용하려고 할 때 종종 NullPointerException 이 발생할 수 있습니다 .
public class MockitoAnnotationsUninitializedUnitTest {
@Mock
List<String> mockedList;
@Test(expected = NullPointerException.class)
public void whenMockitoAnnotationsUninitialized_thenNPEThrown() {
Mockito.when(mockedList.size()).thenReturn(1);
}
}
대부분의 경우 이것은 Mockito 어노테이션을 적절하게 활성화하는 것을 잊어버렸기 때문에 발생합니다.
그래서 우리는 Mockito 어노테이션을 사용하기를 원할 때마다 앞서 설명한 것처럼 추가 단계를 수행하고 초기화해야 함을 명심해야 합니다 .
9. 메모
마지막으로 다음은 Mockito 어노테이션에 대한 몇 가지 참고 사항 입니다.
- Mockito의 어노테이션은 반복적인 모의 생성 코드를 최소화합니다.
- 테스트를 더 읽기 쉽게 만듭니다.
- @Spy 및 @Mock 인스턴스를 모두 주입 하려면 @InjectMocks 가 필요 합니다.
10. 결론
이 짧은 기사에서 우리는 Mockito 라이브러리에서 어노테이션 의 기본 사항을 설명했습니다 .
이 모든 예제의 구현은 GitHub 에서 찾을 수 있습니다 . 메이븐 프로젝트이므로 그대로 임포트하고 실행하기 쉬워야 한다.
물론 더 많은 Mockito 장점을 보려면 여기에서 시리즈를 살펴보십시오 .