Mockito 사용 가이드
Mockito는 자바 기반의 단위 테스트 프레임워크로, 객체의 동작을 모의(mock)하여 테스트를 수행할 수 있게 합니다. 이 가이드에서는 Mockito의 주요 기능들을 실용적인 예제와 함께 설명합니다.
1. 모의 객체(Mock) 생성
Mockito를 사용하면 인터페이스나 클래스에 대한 모의 객체를 생성할 수 있습니다. 모의 객체는 원본 클래스의 모든 메서드를 가지고 있지만, 기본 구현은 간단합니다: void 반환 메서드는 아무 작업도 수행하지 않고, 다른 메서드는 null이나 기본 타입의 값을 반환합니다.
모의 객체 생성 방법
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.List;
import org.junit.jupiter.api.Test;
public class Mockito기본예제 {
@Test
public void 모의객체테스트() throws Exception {
// List 인터페이스에 대한 모의 객체 생성
List<String> 문자열목록 = mock(List.class);
문자열목록.add("테스트값");
// add 메서드가 한 번 호출되었는지 검증
verify(문자열목록, times(1)).add("테스트값");
verify(문자열목록, times(1)).add("다른값");
}
}
Spring Boot에서의 모의 객체 생성
Spring Boot 테스트 환경에서는 @MockBean 어노테이션을 사용하여 모의 객체를 생성할 수 있습니다.
@MockBean
private 학생서비스 학생서비스인스턴스;
2. 스텁(Stubbing) 기능
스텁은 테스트에 필요한 데이터를 객체에 설정하는 기능으로, 상태 기반(state-based) 테스트에 적합합니다. Mockito의 when().thenReturn() 구문을 사용하여 메서드 호출 시 특정 값을 반환하도록 설정할 수 있습니다.
// 테스트 데이터 생성
List<학생> 학생목록 = new ArrayList<>();
학생 학생1 = new 학생();
학생1.set이름("홍길동");
학생목록.add(학생1);
학생 학생2 = new 학생();
학생2.set이름("김철수");
학생목록.add(학생2);
// 스텁 설정
Mockito.when(학생서비스인스턴스.findAll()).thenReturn(학생목록);
3. 검증(Verify) 기능
Mockito의 verify() 메서드를 사용하여 모의 객체의 메서드가 호출되었는지, 호출 횟수는 어떻게 되는지 등을 검증할 수 있습니다.
// 메서드가 한 번 호출되었는지 검증
verify(학생서비스인스턴스, times(1)).findAll();
// 최소 한 번 호출되었는지 검증
verify(학생서비스인스턴스, atLeastOnce()).findAll();
// 최대 한 번 호출되었는지 검증
verify(학생서비스인스턴스, atMostOnce()).findAll();
// 전혀 호출되지 않았는지 검증
verify(학생서비스인스턴스, never()).findAll();
4. 인수 매처(Argument Matchers)
특정 인수 값보다는 인수의 타입이나 일반적인 조건에 따라 모의 객체를 설정해야 할 때가 있습니다. 이때 Argument Matchers를 사용합니다.
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
// 모든 Long 타입 인수에 대해 학생 객체 반환
Mockito.when(학생서비스인스턴스.findById(anyLong())).thenReturn(학생객체);
// 모든 타입의 인수에 대해 학생 객체 반환
Mockito.when(학생서비스인스턴스.findById(any())).thenReturn(학생객체);
// 특정 값에 대해 학생 객체 반환
Mockito.when(학생서비스인스턴스.findById(new Long(10))).thenReturn(학생객체);
5. 스파이(Spy) 사용
같은 클래스 내에서 메서드가 다른 메서드를 호출하는 경우, 스파이 기능을 사용하여 특정 메서드만 모의 객체로 대체할 수 있습니다.
@Service
public class 학생서비스Impl implements 학생서비스 {
public void 테스트메서드(Integer a, Integer b) {
System.out.println("테스트 메서드 시작");
Integer 합 = 더하기(a, b);
System.out.println("테스트 메서드 종료 = " + 합);
}
public Integer 더하기(Integer a, Integer b) {
System.out.println("더하기 메서드");
return a + b;
}
}
스파이를 사용한 테스트 코드:
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(classes = 학생서비스Impl.class)
class 학생서비스ImplTest {
@Autowired
private 학생서비스Impl 학생서비스인스턴스;
@Test
void 테스트메서드테스트() {
// 클래스에 스파이 적용
학생서비스Impl 스파이학생서비스 = Mockito.spy(학생서비스인스턴스);
// 테스트 실행
스파이학생서비스.테스트메서드(3, 4);
// 동일 클래스 내 메서드 호출 검증
Mockito.verify(스파이학생서비스, Mockito.times(1)).더하기(3, 4);
}
}
Spring MVC 컨트롤러 테스트 예제
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@SpringBootTest(classes = 학생컨트롤러.class)
@AutoConfigureMockMvc
public class 학생컨트롤러Test {
@Autowired
private MockMvc mockMvc;
@MockBean
private 학생서비스 학생서비스인스턴스;
@Test
public void 전체조회테스트() throws Exception {
// 테스트 데이터 생성
List<학생> 학생목록 = new ArrayList<>();
학생 학생1 = new 학생();
학생1.set이름("홍길동");
학생목록.add(학생1);
학생 학생2 = new 학생();
학생2.set이름("김철수");
학생목록.add(학생2);
// 스텑 설정
Mockito.when(학생서비스인스턴스.findAll()).thenReturn(학생목록);
// 테스트 실행
mockMvc.perform(MockMvcRequestBuilders.get("/학생/전체조회"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print());
// 메서드 호출 검증
verify(학생서비스인스턴스, times(1)).findAll();
}
}
의존성 추가
Maven을 사용하는 경우, 다음 의존성을 pom.xml에 추가합니다:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
Gradle을 사용하는 경우, build.gradle에 다음을 추가합니다:
testImplementation 'org.mockito:mockito-core:4.5.1'