JUnit에서 Mock 객체를 사용하는 방법은?
_____A1: Mock 객체는 테스트 대상 코드가 의존하는 외부 객체를 대신하는 가짜 객체입니다. 실제 객체와 같은 인터페이스를 구현하지만, 테스트 목적에 맞게 동작을 제어하거나 호출 여부를 검증할 수 있습니다.
Q2: JUnit 테스트에 Mock 객체를 사용하는 이유는 무엇인가요?
A2: Mock을 사용하면 외부 시스템(데이터베이스, 네트워크, API 등)에 접근하지 않고도 독립적인 단위 테스트가 가능합니다. 또한, 복잡한 의존성을 단순화하고 테스트 실행 속도를 높이며, 예외 상황을 쉽게 시뮬레이션할 수 있습니다.
Q3: JUnit과 함께 Mock 객체를 만들 때 주로 사용하는 라이브러리는 무엇인가요?
A3: 가장 흔히 사용하는 Mock 라이브러리는 Mockito입니다. 그 외에도 EasyMock, JMock 등이 있습니다.
Q4: Mockito를 사용해 간단히 Mock 객체를 만드는 방법은?
A4:
```java
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
public class MyServiceTest {
@Test
public void testService() {
// Mock 객체 생성
MyDependency mockDep = mock(MyDependency.class);
// Mock 동작 정의
when(mockDep.someMethod()).thenReturn("mocked response");
// 테스트 대상에 Mock 주입
MyService service = new MyService(mockDep);
// 테스트 실행 및 검증
String result = service.callDependency();
assertEquals("mocked response", result);
// 메서드 호출 검증
verify(mockDep).someMethod();
}
}
```
Q5: Mockito에서 @Mock와 @InjectMocks 어노테이션은 어떻게 사용하나요?
A5:
- `@Mock`은 테스트 클래스 필드에 선언해 Mock 객체를 생성합니다.
사용 예:
```java
@ExtendWith(MockitoExtension.class) // JUnit 5용 확장기능
public class MyServiceTest {
@Mock
private MyDependency myDependency;
@InjectMocks
private MyService myService;
@Test
public void test() {
when(myDependency.someMethod()).thenReturn("mocked");
assertEquals("mocked", myService.callDependency());
}
}
```
Q6: Mockito의 `verify()` 메서드는 무엇을 하나요?
A6: 특정 Mock 객체의 메서드가 지정된 횟수만큼 호출되었는지를 검증합니다. 예를 들어 `verify(mockDep, times(1)).someMethod()`는 `someMethod()`가 정확히 한 번 호출됐는지를 확인합니다.
Q7: 테스트에서 Mock 객체의 행동을 설정하는 메서드들은 어떤 것이 있나요?
A7: 대표적으로 `when(...).thenReturn(...)` (리턴값 지정), `when(...).thenThrow(...)` (예외 던짐), `doNothing()`, `doThrow()` 등이 있습니다.
Q8: JUnit 4에서 Mockito Mock 객체를 초기화하려면 어떻게 하나요?
A8: 테스트 클래스에 `@RunWith(MockitoJUnitRunner.class)`를 선언하거나, `@Before` 메서드에서 `MockitoAnnotations.initMocks(this)`를 호출해야 합니다.
Q9: Mock 대신 Spy를 사용하는 경우는 언제인가요?
A9: Spy는 실제 객체를 감싸며, 일부 메서드만 Mock하거나 호출 횟수를 확인하고 싶을 때 사용합니다. 반면 Mock은 완전히 Mock 객체를 만듭니다.
Q10: Mock 객체 사용 시 주의할 점은 무엇인가요?
A10:
- Mock이 너무 많으면 테스트가 오히려 복잡해질 수 있습니다.
- 비즈니스 로직이 아닌 Mock 설정에 집중하는 우를 피해야 합니다.
- Mock 대상이 잘 설계된 인터페이스 또는 클래스로 구성되어야 유지보수가 용이합니다.
---
요약: JUnit 테스트에서 Mock 객체는 Mockito 같은 라이브러리를 이용해 생성하며, `mock()`, `@Mock`, `@InjectMocks`, `when`, `verify` 등의 API를 사용해 생성, 동작 정의, 주입, 호출 검증 등이 이루어진다. 이를 활용해 외부 의존성을 격리하고 독립적인 단위 테스트를 효과적으로 수행할 수 있다.
Mock 객체는 실제 객체를 대체하여 테스트할 때 의존성이나 외부 시스템에 의존하지 않고도 특정 동작을 시뮬레이션할 수 있게 해줍니다.
JUnit 자체에는 Mock 기능이 포함되어 있지 않아서 일반적으로 Mockito, EasyMock, JMock 같은 mocking 프레임워크와 함께 사용합니다.
가장 널리 쓰이는 Mockito를 기준으로 설명하겠습니다.
1. Mockito 라이브러리 추가 먼저, 프로젝트에 Mockito 라이브러리를 포함해야 합니다.
Gradle, Maven 등 빌드 도구에 따라 의존성을 추가합니다.
예를 들어, Gradle 기준: ```gradle testImplementation 'org.mockito:mockito-core:4.+' // 최신 버전을 확인해서 적용 ``` ---
2. 기본적인 Mock 객체 생성 Mockito를 사용해서 가장 간단하게 Mock 객체를 만드는 방법입니다.
```java import static org.mockito.Mockito.mock; public class MyServiceTest { @Test public void testWithMock() { MyRepository mockRepository = mock(MyRepository.class); // 이제 mockRepository는 MyRepository 인터페이스(혹은 클래스)의 Mock 객체입니다.
} } ``` 이렇게 만든 mock 객체는 실제 객체처럼 메서드를 호출할 수 있지만, 기본적으로 아무 동작도 하지 않고 null이나 기본값을 리턴합니다.
---
3. Mock 객체에 동작 정의하기 (Stubbing) Mock 객체는 기본 동작이 없으므로, 특정 메서드가 호출됐을 때 원하는 값을 반환하도록 정의할 수 있습니다.
이를 Stubbing이라고 합니다.
```java import static org.mockito.Mockito.when; @Test public void testStub() { MyRepository mockRepository = mock(MyRepository.class); when(mockRepository.findById(1L)).thenReturn(new User(1L, "Alice")); User user = mockRepository.findById(1L); assertEquals("Alice", user.getName()); } ``` `when(...).thenReturn(...)` 구문을 통해 특정 입력값에 대해 결과를 미리 정의해 둘 수 있습니다.
---
4. Mock 객체를 JUnit 테스트에 주입하기 Mock 객체를 직접 만들고 주입해도 되지만, Mockito의 어노테이션을 이용하면 더욱 편리합니다.
```java import org.mockito.Mock; import org.mockito.InjectMocks; import org.mockito.junit.jupiter.MockitoExtension; import org.junit.jupiter.api.extension.ExtendWith; @ExtendWith(MockitoExtension.class) public class MyServiceTest { @Mock private MyRepository myRepository; // 자동으로 Mock 객체 생성 @InjectMocks private MyService myService; // myRepository가 주입된 MyService 객체 생성 @Test public void testService() { when(myRepository.findById(1L)).thenReturn(new User(1L, "Bob")); User user = myService.getUserById(1L); assertEquals("Bob", user.getName()); } } ``` - `@Mock`은 Mock 객체를 자동으로 생성. - `@InjectMocks`는 Mock 객체를 의존성으로 주입하여 실제 테스트 대상 객체를 생성. - `@ExtendWith(MockitoExtension.class)`는 Mockito 어노테이션을 활성화. ---
5. Mock 객체의 호출 검증 (Verification) 단순히 반환값을 정의하는 것 외에, 특정 메서드가 호출됐는지 검증할 수 있습니다.
```java import static org.mockito.Mockito.verify; @Test public void testVerification() { MyRepository mockRepository = mock(MyRepository.class); MyService myService = new MyService(mockRepository); myService.getUserById(1L); verify(mockRepository).findById(1L); // findById(1L) 호출 여부 검증 } ``` 이렇게 하면 테스트 실패 시 메서드가 호출되지 않은 경우 알람을 받을 수 있습니다.
---
6. 예외 던지기, 특정 횟수 호출 등 고급 기능 - 특정 메서드가 호출되면 예외를 던지도록 만들 수도 있습니다.
```java when(mockRepository.findById(2L)).thenThrow(new RuntimeException("Not found")); ``` - 메서드 호출 횟수 검증: ```java verify(mockRepository, times(
2)).findById(1L); ``` - 호출되지 않음을 검증할 수도 있습니다.
```java verify(mockRepository, never()).delete(any()); ``` ---
7. 전체적인 흐름 요약 1. Mockito 라이브러리를 프로젝트에 추가한다.
2. `mock()` 메서드나 `@Mock` 어노테이션으로 Mock 객체를 생성한다.
3. `when(...).thenReturn(...)` 형태로 Mock 객체의 동작을 정의한다.
4. 실제 테스트 대상에 Mock 객체를 주입(`@InjectMocks` 활용 가능).
5. 테스트 수행 후 `verify()`를 통해 Mock 객체의 메서드 호출을 검증한다.
--- 마무리 - Mock 객체는 외부 의존성을 격리하여 단위 테스트를 용이하게 만든다. - Mockito는 JUnit과 함께 사용할 때 직관적이고 풍부한 기능을 제공한다.
- 적절한 Mock 사용은 테스트 코드의 안정성과 유지보수성을 크게 높여준다. 이상으로 JUnit에서 Mock 객체를 사용하는 방법에 대해 Mockito를 중심으로 자세히 설명해 드렸습니다.
추가 질문이 있으시면 언제든지 말씀해 주세요.
작성자:
김하윤 [비회원]
| 작성일자: 1년 전
2025-05-26 02:50:46
조회수: 198 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
조회수: 198 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
내용이 부정확하다면 싫어요를 클릭해주세요.