티스토리 뷰
[Spring] BDD 패턴의 테스트 코드 작성 시 Mockito의 어색함과 BDDMockito의 활용
heemang.dev 2024. 10. 11. 13:44
Mockito와 BDDMockito 둘 다 Java 기반의 테스트 프레임워크로, 모킹(mocking)을 지원한다. 이 둘은 기능상에 차이점은 없으나, 모킹하는 스타일 방식이 차이가 있다.
1. Mockito를 통해 Mock 객체 생성하는 방법
@Mock 애너테이션을 통해 Mock 객체를 생성하고, @InjectMocks 애너테이션을 통해 Mock 객체를 주입할 수 있다. 예를 들어, MailService 객체를 생성하기 위해서 MailSendClient와 MailSendHistoryRepository가 필요하다. 이를 위해 @Mock 애너테이션을 사용하여 MailSendClient와 MailSendHistoryRepository 클래스의 Mock 객체를 생성하고, @InjectMocks 애너테이션을 통해 이 Mock 객체들을 MailService에 주입할 수 있다.
@ExtendWith(MockitoExtension.class)
class MailServiceTest {
@Mock
private MailSendClient mailSendClient;
@Mock
private MailSendHistoryRepository mailSendHistoryRepository;
@InjectMocks
private MailService mailService;
}
2. 행위 주도 개발(BDD, Behavior-Driven Development)
BDD란 행위 주도 개발이라고 불리며, TDD에서 착안한 방법론이다. TDD에서 발전된 개념으로, 사용자 요구사항에 맞춘 시스템의 행동에 초점을 맞춰 개발 및 테스트 과정을 진행한다.
2-1. BDD의 특징
- BDD는 사용자가 어떻게 사용할 것인가에 중점을 둔다. 즉, 시스템이 특정 입력을 받으면 어떤 행동을 해야 하는지를 작성한다.
- Given-When-Then 패턴 : BDD에서는 테스트 시나리오는 Given-When-Then 구조로 작성한다.
- Given : 어떤 초기 상태가 주어졌을 때 (테스트 전제 조건)
- When : 특정 행동이 일어났을 때 (테스트 대상 동작)
- Then : 기대하는 결과가 나와야 한다. ( 테스트 결과 검증)
2-2. Given-When-Then 예시
- given : sendEmail() 메서드가 호출되었을 때, 해당 메서드는 true를 반환하도록 설정한다.
- anyString() : 어떤 문자열이 들어와도 상관없다.
- when : sendMail() 메서드를 호출한다.
- then : sendMail() 메서드가 호출되었을 때, 그 결과는 true여야 한다.
@ExtendWith(MockitoExtension.class)
class MailServiceTest {
@Mock
private MailSendClient mailSendClient;
@Mock
private MailSendHistoryRepository mailSendHistoryRepository;
@InjectMocks
private MailService mailService;
@Test
@DisplayName("메일 전송 테스트")
void sendMail() {
//given
when(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString()))
.thenReturn(true);
//when
boolean result = mailService.sendMail("", "", "", "");
//then
assertThat(result).isTrue();
verify(mailSendHistoryRepository, times(1)).save(any(MailSendHistory.class));
}
}
@RequiredArgsConstructor
@Service
public class MailService {
private final MailSendClient mailSendClient;
private final MailSendHistoryRepository mailSendHistoryRepository;
public boolean sendMail(String fromEmail, String toEmail, String subject, String content) {
boolean result = mailSendClient.sendEmail(fromEmail, toEmail, subject, content);
if (result) {
mailSendHistoryRepository.save(
MailSendHistory.create(fromEmail, toEmail, subject, content)
);
return true;
}
return false;
}
}
3. Mockito를 사용하는 테스트 코드의 어색함
테스트 코드를 작성할 때, BDD 형식에 맞추어 작성하기 위해 Given-When-Then 절을 사용하였다. 그러나 아래 코드를 보면 when() 메서드를 사용하여 테스트 전제 조건을 설정하고 있다. 전제 조건을 설정하는 것이므로 given 절에 위치하는 것이 맞지만, when() 메서드와 given 절 사이에서 어색함이 발생한다.
Mockito의 when() 메서드는 TDD 패턴에 맞춰진 방식으로, BDD 스타일의 Given-When-Then 패턴과는 약간의 차이가 발생한다.
@ExtendWith(MockitoExtension.class)
class MailServiceTest {
@Mock
private MailSendClient mailSendClient;
@Mock
private MailSendHistoryRepository mailSendHistoryRepository;
@InjectMocks
private MailService mailService;
@Test
@DisplayName("메일 전송 테스트")
void sendMail() {
//given
Mockito.when(mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString()))
.thenReturn(true);
//when
boolean result = mailService.sendMail("", "", "", "");
//then
assertThat(result).isTrue();
verify(mailSendHistoryRepository, times(1)).save(any(MailSendHistory.class));
}
}
4. BDDMockito를 사용하여 BDD 스타일에 맞춰 테스트 코드 작성하기
BDDMockito는 Mockito를 상속받아 BDD 스타일의 테스트 작성을 지원한다. BDDMockito는 Mockito와 동일한 기능을 제공하면서도 Given-When-Then 패턴을 직관적으로 사용할 수 있도록 설계되었다. 따라서 Mockito 기능을 기반으로 BDD 패턴에 맞는 표현을 사용하여 더 직관적인 테스트 코드 작성을 돕는다.
- Mockito : when().thenReturn()
- BDDMockito : given().willReturn()
@ExtendWith(MockitoExtension.class)
class MailServiceTest {
@Mock
private MailSendClient mailSendClient;
@Mock
private MailSendHistoryRepository mailSendHistoryRepository;
@InjectMocks
private MailService mailService;
@Test
@DisplayName("메일 전송 테스트")
void sendMail() {
//given
BDDMockito.given(
mailSendClient.sendEmail(anyString(), anyString(), anyString(), anyString()))
.willReturn(true);
//when
boolean result = mailService.sendMail("", "", "", "");
//then
assertThat(result).isTrue();
verify(mailSendHistoryRepository, times(1)).save(any(MailSendHistory.class));
}
}
5. 결론
Mockito와 BDDMockito 둘 다 모킹 기능을 제공하지만, BDD 패턴에 맞추어 테스트 코드를 작성할 때 Mockito를 사용하는 경우 약간의 어색함이 발생한다. 이는 when() 메서드를 Given 절에 사용하는 것이 BDD 흐름과 맞지 않기 때문이다.
따라서 BDDMockito를 사용하여 Given-When-Then 구조에 맞춰 더 직관적이고 자연스러운 테스트 코드 작성이 가능하다.