Mockito는 테스트할 때 자주 쓰이는 Mock 객체 생성용 라이브러리다.
1️⃣ Mock 객체란?
Mock 객체는 말 그대로 가짜 객체다.
실제 객체처럼 동작하지만, 내부 로직은 없고 우리가 원하는 대로 행동을 지정할 수 있다. 즉, "흉내만 내는 객체"다.
📝 예시:
public interface EmailService {
void sendEmail(String to, String message);
}
→ 진짜 구현은 메일을 보내겠지만,
테스트할 땐 진짜 메일을 보내면 안 되니까 Mock 객체로 대체
그럼 "흉내만 낸다"는 건 무슨 뜻일까?
// 실제 클래스 (진짜 메일을 보냄)
public class NotificationService {
public void send(String message) {
System.out.println("Sending message: " + message);
}
}
// 테스트 대상 클래스
public class UserService {
private final NotificationService notificationService;
public UserService(NotificationService notificationService) {
this.notificationService = notificationService;
}
public void register(String username) {
notificationService.send("Welcome, " + username + "!");
}
}
이제 위 코드를 테스트한다고 해보자.
진짜 NotificationService를 쓰면 콘솔에 출력되거나 진짜 메일이 보내질 수 있다.
그래서 Mock 객체로 흉내만 내고, 호출됐는지만 확인하는 것.
// Mockito로 만든 Mock 객체 예시
import static org.mockito.Mockito.*;
public class UserServiceTest {
@Test
void register_shouldSendWelcomeMessage() {
NotificationService mockNotification = mock(NotificationService.class); // 가짜 생성
UserService userService = new UserService(mockNotification); // 주입
userService.register("minjae");
verify(mockNotification).send("Welcome, minjae!"); // 호출됐는지 검증
}
}
📌 실제 객체 vs Mock 객체 비교
구분 | 실제 객체 | Mock 객체 (흉내만 냄) |
---|---|---|
동작 | 진짜 일을 함 (메일 발송 등) | 아무 동작도 안 함 |
목적 | 실제 서비스용 | 테스트용 (동작 기록만) |
메서드 기록 | 안됨 | verify() 로 검증 가능 |
예시 생성 | new NotificationService() |
mock(NotificationService.class) |
즉, Mock 객체는 진짜 일을 하지 않고 "그런 척만" 하기 때문에
테스트할 때 안전하고 빠르며, 외부 시스템 없이 동작을 검증할 수 있다.
2️⃣ 왜 Mock 객체를 사용할까?
테스트 대상 클래스가 의존하는 외부 객체(서비스, DB 등)를 대체해서:
- 테스트 속도 빠르게
- 외부 환경 영향 없이
- 단위 테스트만 정확하게
예시:
public class UserService {
private EmailService emailService;
public void registerUser(String email) {
// 회원가입 로직
emailService.sendEmail(email, "Welcome!");
}
}
이런 상황에서 진짜 메일 보내면 안 되니까
→ EmailService
를 Mock 객체로 대체
3️⃣ Mockito로 Mock 객체 만들기
Mock 객체는 직접 주입하거나, 자동으로 주입하는 방식이 있다.
☝️방법 1 - 직접 주입 (생성자나 세터를 통해)
@Mock
EmailService emailService;
@BeforeEach
void setup() {
userService = new UserService(emailService); // 직접 주입
}
✌🏻방법 2 - @InjectMocks 사용 (자동 주입)
@Mock
EmailService emailService;
@InjectMocks
UserService userService;
이 경우, UserService
안에 EmailService
가 자동으로 주입되도록 설정되는데,
이 기능은 Mockito가 테스트 실행 시 개입할 수 있어야만 동작한다.
이 때, 필요한 게 바로 @ExtendWith(MockitoExtension.class)
JUnit5 환경에서 Mockito 어노테이션이 동작하도록 도와주는 어댑터 역할이다.
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
EmailService emailService;
@InjectMocks
UserService userService;
@Test
void testRegisterUser() {
userService.registerUser("test@example.com");
verify(emailService).sendEmail("test@example.com", "Welcome!");
}
}
만약 @ExtendWith
를 붙이지 않으면, @Mock
과 @InjectMocks
가 적용되지 않고 null
에러가 날 수 있다.
구분 | 유무 | 설명 |
---|---|---|
@ExtendWith 없음 | ❌ | Mock 객체 생성 안 됨, null 발생 |
@ExtendWith 있음 | ✅ | Mockito가 개입해서 어노테이션 자동 처리 가능 |
📝 프레임워크 vs 라이브러리 차이
구분 | 라이브러리 | 프레임워크 |
---|---|---|
제어 흐름 | 우리가 호출 | 프레임워크가 우리 코드를 호출 |
의존성 주입 | 직접 해야 함 | 자동으로 해줌 |
대표 예 | Mockito, Lombok | Spring, Django |
Mockito는 우리가 호출해서 써야 하는 라이브러리다.
자동으로 객체를 생성하고 주입해주진 않기 때문에 프레임워크는 아니다.
✅ 정리
- Mock 객체 = 테스트용 가짜 객체
- Mockito = Mock 객체를 쉽게 만들도록 도와주는 라이브러리
- 프레임워크는 객체 생성과 주입을 자동으로 해주는 것 (ex. Spring)
'spring' 카테고리의 다른 글
싱글톤 Context에서 전략 패턴 사용 시 동시성 문제 (0) | 2025.03.27 |
---|---|
ThreadLocal, 안 쓰면 큰일 나는 이유 (멀티스레드 동시성 문제 해결법) (0) | 2025.03.20 |
스프링 MVC 학습목록 (2) (0) | 2025.01.08 |
HandlerMapping & RequestMapping (0) | 2024.12.02 |
SpringMVC ArgumentResolver (0) | 2024.12.02 |
댓글