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 를 사용하여 모의 wordMapMyDictionary 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 장점을 보려면 여기에서 시리즈를 살펴보십시오 .

Junit footer banner