Spring 기반의 웹 어플리케이션 개발 시 테스트를 도와주는 도구이다. 테스트하고 싶은 객체가 다른 객체를 주입받아 동작한다면 테스트가 어려울 수 있다. 개발자가 원하는 객체에 관한 테스트만 진행할 수 있도록 의존성을 갖고 있는 다른 객체를 가짜 객체 로 대체해여 테스트할 수 있도록 도와준다.

Mock 객체 의존성 주입

Mockito 에서 가짜 객체의 의존성 주입 을 위해서는 크게 3가지 어노테이션이 사용된다.

예를 들어, controller 에 대한 단위테스트를 진행한다고 하자. controller 에서 service 를 주입받는다면 service 를 @Mock 을 이용해 가짜 객체로 생성하고 @InjectMocks 를 통해 controller 에 주입시킨다.

Mockito 와 JUnit 의 결합

Mockito 도 테스팅 프레임워크이기 때문에 JUnit 과 결합되기 위해서는 별도의 작업이 필요하다. 기존의 JUnit4 에서는 @RunWith(MockitoJUnitRunner.class) 를 붙여 연동시켰다. 하지만 SpringBoot 2.2.0 부터 공식적으로 JUnit5 를 지원하여 @ExtendWith(MockitoExtension.class) 를 붙여야 연동이 가능하다.

@DisplayName("지하철 노선 관련 service 테스트")
@ExtendWith(MockitoExtension.class)
class LineServiceTest {

    private static final Line LINE = new Line("신분당선", "bg-red-600");

    @Mock
    private LineDao lineDao;

    @InjectMocks
    private LineService lineService;

		// 생략
}

위의 예시 코드는 우테코 지하철 노선도 미션에서 지하철 노선 Service 테스트의 일부 코드이다. Service 계층에서 Dao 를 주입받아 사용하므로 가짜 객체로 StationDao 를 생성했고, 그 가짜 객체를 StationService 에 주입시켰다. Mockito 라이브러리를 사용하기 위해서 @ExtendWith(MockitoExtension.class) 도 선언해주었다.

예시코드

@DisplayName("지하철 노선을 생성한다.")
@Test
void save() {
    // when
    long lineId = lineService.save(LINE);

    // mocking
    given(lineDao.find(any()))
            .willReturn(Optional.of(LINE));

    // then
    assertThat(lineService.find(lineId)).isEqualTo(lineService.find(lineId));
}

가짜 객체가 예상대로 올바르게 동작하기 위해서는 설정이 필요하다. 위의 코드는 지하철 노선도 정보를 생성하는 테스트코드이다. Service 객체를 이용하여 save() 메서드를 호출한다. 실제로 DB 와 연결되어 있지 않고 Dao 는 가짜 객체이므로 테스트가 실패할 것이다. lineService 의 find() 는 lineDao 의 find() 를 호출하므로 정상동작할 경우의 결과를 미리 설정해두었다.

https://mangkyu.tistory.com/145

라이브러리 사용 시 주의할 점

PotentialStubbingProblem 예외 발생!
// mockito 라이브러리의 권장 방식
doReturn(false)
		.when(stationDao).existStationById(1L);

// mockito 라이브러리의 비권장 방식
given(stationDao.existStationById(1L))
		.willReturn(false);

원인은 순차적으로 같은 메서드를 호출할 때, 값에 따라 결과가 달라졌어야 하는데 하나의 경우에만 설정하여 오류남 그러면서 mockito 라이브러리가 권장하는 방식을 찾았음

https://www.freeism.co.kr/wp/archives/2243