Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- 1차원 DP
- 2차원 dp
- 99클럽
- @BeforeAll
- @BeforeEach
- @Builder
- @Entity
- @GeneratedValue
- @GenericGenerator
- @NoargsConstructor
- @Query
- @Table
- @Transactional
- Actions
- Amazon EFS
- amazon fsx
- Android Studio
- ANSI SQL
- ApplicationEvent
- assertThat
- async/await
- AVG
- AWS
- Azure
- bind
- builder
- button
- c++
- c++ builder
- c03
Archives
- Today
- Total
기록
[Mock] 스프링 환경에서 외부 시스템 테스트하기 본문
1. Mock을 사용하는 상황과 사용하지 않는 상황
1.1 Mock을 사용하는 상황
외부 시스템과 연계되는 테스트에서 Mock 객체를 사용하면 외부 의존성을 제거하고 독립적으로 동작을 검증할 수 있습니다. 예를 들어, 이메일 전송, API 호출 등 외부 서비스에 의존하는 로직은 Mock 객체로 대체하여 테스트에서 외부 시스템의 영향을 배제해야 합니다.
1.2 Mock을 사용하지 않는 상황
내부 로직만 검증하는 테스트에서는 실제 객체를 사용하여 테스트를 수행하는 것이 적합합니다. 이 경우 실제 객체의 동작을 통해 로직의 정확성을 확인할 수 있습니다.
1.3 Classicist vs Mockist 논쟁
Mock 사용 여부와 관련된 논쟁으로 Classicist 접근법과 Mockist 접근법이 있습니다.
- Classicist 접근법: 실제 객체를 사용하여 테스트를 작성합니다. 외부 시스템과의 인터페이스나 컨트롤러 단에서만 Mock 객체를 사용합니다. 이를 통해 테스트가 실제 동작에 더 가깝도록 유지합니다.
- Mockist 접근법: 모든 의존성을 Mock 객체로 대체하여 테스트를 작성합니다. 독립적이고 빠른 테스트가 가능하지만, Mock 설정 및 유지보수가 복잡해질 수 있습니다.
2. Mockito의 주요 어노테이션
Mockito는 다음과 같은 어노테이션을 통해 다양한 테스트 시나리오를 지원합니다.
2.1 스프링 컨텍스트를 사용하지 않는 어노테이션
- @Mock: Mock 객체를 생성하여, 해당 객체의 동작을 개발자가 원하는 대로 정의할 수 있도록 합니다.
외부 의존성을 제거하고 특정 동작만을 테스트할 때 사용합니다. 객체를 완전히 Mock으로 처리하며, 실제 로직은 동작하지 않습니다.
- @Spy: 실제 객체를 생성하면서도 필요에 따라 Mocking 동작을 추가할 수 있습니다.
객체의 일부 메서드는 실제 동작을 테스트하고, 다른 메서드는 Mocking이 필요할 때 사용합니다. 실제 객체와 Mock 객체의 장점을 결합하여 유연하게 사용할 수 있습니다. - @InjectMocks: @Mock 또는 @Spy로 생성된 객체를 주입합니다.
테스트 대상 객체에 의존성을 자동으로 주입하여 테스트를 간소화합니다. 의존성 주입이 필요한 객체를 Mocking된 의존성을 사용해 초기화합니다.
어노테이션 | 실제 객체 생성 여부 | Mocking 가능 범위 | 사용 사례 |
@Mock | X | 모든 메서드 | 외부 의존성 제거, 독립적인 단위 테스트 수행 |
@Spy | O | 선택적 메서드 | 부분 Mocking으로 실제 동작과 조합된 테스트 수행 |
@InjectMocks | N/A | N/A | 의존성이 많은 객체를 테스트할 때 |
2.2 스프링 컨텍스트를 사용하는 어노테이션
- @MockBean: 스프링 컨텍스트에 Mock 객체를 등록하여 통합 테스트에 사용합니다.
스프링 컨텍스트에 직접 등록되며, 다른 빈과의 의존성 관계가 유지됩니다. 외부 의존성을 제거한 상태에서 통합 테스트를 수행할 때 주로 사용됩니다. - @SpyBean: 실제 빈을 Spy로 래핑하여 부분적인 Mocking이 가능합니다.
실제 빈의 일부 메서드는 원래의 동작을 유지하며, 필요한 메서드만 Mocking이 가능합니다. 실제 동작을 테스트하면서 일부 Mocking을 병행해야 하는 경우 유용합니다.
어노테이션 | 실제 객체 생성 여부 | 스프링 컨텍스트와의 연계 | 사용 사례 |
@MockBean | X | O | 외부 의존성 제거, 스프링 기반 통합 테스트 수행 |
@SpyBean | O | O | 실제 동작과 부분적인 Mocking 조합이 필요한 경우 |
3. BDD 스타일과 Mockito.when()
Mockito는 전통적인 방식의 when() 메서드와 BDD 스타일의 given() 메서드를 지원합니다. BDD 스타일은 테스트 코드의 가독성을 높이고, "Given-When-Then" 흐름을 명확히 표현할 수 있도록 돕습니다.
- Mockito.when(): 전통적인 방식으로 특정 조건에서 Mock 객체의 동작을 정의합니다.
- BDDMockito.given(): BDD 스타일로 작성된 테스트에서 사용됩니다.
when(userRepository.findById(1L)).thenReturn(Optional.of(mockUser)); // Mockito
given(userRepository.findById(1L)).willReturn(Optional.of(mockUser)); //BDD
4. MailServiceTest 예제 분석
MailService는 이메일 전송과 같은 외부 서비스를 호출하는 책임을 담당합니다. 실제 테스트에서 외부 시스템과의 통신은 네트워크 상태, 서비스 가용성 등의 변수로 인해 테스트의 신뢰성을 떨어뜨릴 수 있습니다. 따라서 이러한 외부 의존성을 배제하고, 안정적인 테스트 환경을 구성하기 위해 Mock 객체를 사용하는 것이 적합합니다.
4.1 Mock 객체 생성과 Stubbing
Mock 객체를 사용하여 외부 의존성을 모방하며, 테스트하려는 동작에만 집중할 수 있도록 합니다. 이를 통해 예측 가능한 결과를 얻고 테스트의 신뢰성을 높입니다.
@Mock
private EmailClient emailClient;
@InjectMocks
private MailService mailService;
@Test
void testSendEmail() {
// Stubbing
given(emailClient.send("test@example.com", "Hello")).willReturn(true);
// 실행
boolean result = mailService.sendEmail("test@example.com", "Hello");
// 검증
assertTrue(result);
verify(emailClient).send("test@example.com", "Hello");
}
'교육 > 강의' 카테고리의 다른 글
[테스트전략] Test Fixture 독립성 보장 (0) | 2025.02.10 |
---|---|
[테스트전략] 각 테스트는 하나의 목적만 가진다 (0) | 2025.02.09 |
[JpaTest] CQRS와 서비스 레이어에서의 트랜잭션 관리 (0) | 2025.02.05 |
[JpaTest] Spring Bean Validation 활용 가이드 (0) | 2025.02.04 |
[JpaTest] Spring Layered Architecture와 Layer 테스트 전략 (0) | 2025.02.03 |
Comments