Mockito는 Java에서 단위 테스트를 위한 모킹 프레임워크입니다.

참고 자료

초기 설정

의존성 추가 (Android/Gradle)

testCompile 'org.mockito:mockito-core:1.10.19'
testCompile 'junit:junit:4.12'

테스트 클래스 설정

@RunWith(MockitoJUnitRunner.class)
public class PortfolioTester {
}

Mockito 클래스의 멤버들을 static import하여 사용합니다.

Mock 생성

@Mock 어노테이션 사용

@Mock
StockService stockService;

mock() 메서드 사용

stockService = mock(StockService.class);

mock()은 메서드 호출 순서에 상관없이 mock을 생성합니다.

Mock 주입

// @InjectMocks는 mock 객체를 생성하고 주입합니다
@InjectMocks
MathApplication mathApplication = new MathApplication();

// @Mock은 주입될 mock 객체를 생성합니다
@Mock
CalculatorService calcService;

Mocking Method

기본 사용법

when(stockService.getPrice(googleStock)).thenReturn(50.00);
when(stockService.getPrice(microsoftStock)).thenReturn(1000.00);

어떤 값이든 매칭 (any)

when(list.get(anyInt())).thenReturn("dfdf");

호출할 때마다 다른 값 반환

when(stockService.getPrice(googleStock))
    .thenReturn(50.00)
    .thenReturn(100.00)
    .thenReturn(150.00);
// 첫 호출: 50, 두번째: 100, 세번째: 150

예외 발생시키기

doThrow(new RuntimeException("divide operation not implemented"))
   .when(calcService).add(10.0, 20.0);

커스텀 응답 (Answer)

when(calcService.add(any(), 10.0)).thenAnswer(new Answer<Double>() {
   @Override
   public Double answer(InvocationOnMock invocation) throws Throwable {
      Object[] args = invocation.getArguments();
      Object mock = invocation.getMock();
      return 30.0;
   }
});

Spy

실제 인스턴스를 사용하면서 호출을 감시합니다. 실제 로직 대신 테스트용으로 간단하게 구현할 수 있습니다.

// 실제 객체에 spy 생성
calcService = spy(calculator);

// 실제 객체의 동작 테스트
Assert.assertEquals(mathApplication.add(20.0, 10.0), 30.0, 0);

Mock 초기화

reset(calcService);

Verify

메서드 호출 확인

Assert.assertEquals(mathApplication.add(10.0, 20.0), 30.0, 0);

// 같은 인자로 호출되었는지 확인
verify(calcService).add(10.0, 20.0);

호출 횟수 검증

verify(calcService, times(1)).add(10.0, 20.0);
verify(calcService, never()).multiply(10.0, 20.0);

기타 옵션:

  • atLeast(int min) - 최소 min번 호출
  • atLeastOnce() - 최소 1번 호출
  • atMost(int max) - 최대 max번 호출

호출 순서 검증

InOrder inOrder = inOrder(calcService);

// add가 먼저 호출되고, subtract가 나중에 호출되었는지 확인
inOrder.verify(calcService).add(20.0, 10.0);
inOrder.verify(calcService).subtract(20.0, 10.0);

처리 시간 검증

spy로 실제 객체의 처리 시간을 체크할 때 유용합니다.

// add()가 100ms 내에 호출되면 통과
verify(calcService, timeout(100)).add(20.0, 10.0);

API 호출 테스트 예제 (Captor 사용)

public class RepositoryUnitTest {
    @Mock
    private RepositoryContract.View view;

    @Mock
    private ProgressBarProvider progressBarProvider;

    @Mock
    private GitHubAPI gitHubAPI;

    @Mock
    private Call<List<Repository>> mockCall;

    @Captor
    private ArgumentCaptor<Callback<List<Repository>>> captor;

    private RepositoryPresenter presenter;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        presenter = new RepositoryPresenter(gitHubAPI, progressBarProvider);
        presenter.setView(view);
    }

    @Test
    public void test_getRepositories() {
        // arrange
        String user = BuildConfig.GITHUB_OWNER;
        List<Repository> repositories = new ArrayList<>();
        repositories.add(new Repository());
        when(gitHubAPI.GetRepos(user)).thenReturn(mockCall);
        Response<List<Repository>> response = Response.success(repositories);

        // act
        presenter.start();

        // assert
        verify(mockCall).enqueue(captor.capture());
        captor.getValue().onResponse(null, response);
        verify(progressBarProvider).showProgressBar();
        verify(progressBarProvider).hideProgressBar();
        verify(view).updateRepositoryList(repositories);
    }
}