기존에 @SpringbootTest 어노테이션를 사용하여 Service 계층을 테스트하였습니다. 그러나 실제 DB와 관련된 Repository 계층 등을 직접 주입받아야 했고, 이렇게 된다면 service 계층만의 단위 테스트를 제대로 하지 못할 것이라는 판단을 하였습니다. 따라서 Mockito를 사용하여 리팩토링하였는데, 이 과정을 포스팅하려 합니다.
Service 계층 단위 테스트 - 기존의 코드
@SpringBootTest
@Transactional(readOnly = true)
@ExtendWith(MockitoExtension.class)
class TicketInformationServiceTest {
@Autowired
private TicketInformationRepository ticketInformationRepository;
@Autowired
private SubPaymentRepository subPaymentRepository;
@Autowired
private PaymentCancelRuleRepository paymentCancelRuleRepository;
@Autowired
private AgreementRepository agreementRepository;
@Test
@Transactional
void saveTicketInformation() {
// given
TicketInformation ticketInformation = TicketInformation.builder()
.ticketName("ticketName")
.ticketSubName("ticketSubName")
.ticketCount(4)
.ticketPrice(1000)
.build();
Agreement agreement = Agreement.builder()
.privacyToThirdParty(1)
.stayRule(1)
.conciergeRule(1)
.ageOver14(1)
.build();
PaymentCancelRule paymentCancelRule = PaymentCancelRule.builder()
.content("asd")
.build();
paymentCancelRuleRepository.save(paymentCancelRule);
agreementRepository.save(agreement);
SubPayment subPayment = SubPayment
.builder()
.agreement(agreement)
.paymentCancelRule(paymentCancelRule)
.build();
subPaymentRepository.save(subPayment);
ticketInformation.setSubPayment(subPayment);
ticketInformationRepository.save(ticketInformation);
//when
TicketInformation foundTicketInformation = ticketInformationRepository.findById(ticketInformation.getId())
.orElse(null);
//then
assertEquals("ticketName",foundTicketInformation.getTicketName());
assertEquals("ticketSubName", foundTicketInformation.getTicketSubName());
assertEquals(4, foundTicketInformation.getTicketCount());
assertEquals(1000, foundTicketInformation.getTicketPrice());
assertEquals(subPayment, foundTicketInformation.getSubPayment());
assertEquals(foundTicketInformation, subPayment.getTicketInformationList().get(0));
}
}
test 코드에서 보듯 @Autowired, @SpringbootTest 등을 통해 실제로 DB에 접근하여 테스트를 진행하였습니다.
Service 계층 단위 테스트 - Mockito 코드
@ExtendWith(MockitoExtension.class)
class TicketInformationServiceTest {
@Mock
TicketInformationRepository ticketInformationRepository;
@Mock
SubPayment subPayment;
@InjectMocks
TicketInformationService ticketInformationService;
@Test
void saveTicketInformation() {
// given
PaymentTicketRequestDto paymentTicketRequestDto = new PaymentTicketRequestDto();
paymentTicketRequestDto.setTicketName("ticketName");
paymentTicketRequestDto.setTicketSubName("ticketSubName");
paymentTicketRequestDto.setTicketCount(4);
paymentTicketRequestDto.setTicketPrice(1000);
TicketInformation ticketInformation = TicketInformation.builder()
.ticketName("ticketName")
.ticketSubName("ticketSubName")
.ticketCount(4)
.ticketPrice(1000)
.build();
ticketInformation.setSubPayment(subPayment);
given(ticketInformationRepository.save(any(TicketInformation.class))).willReturn(ticketInformation);
// when
TicketInformation savedTicketInformation = ticketInformationService.saveTicketInformation(subPayment, paymentTicketRequestDto);
// then
assertEquals("ticketName",savedTicketInformation.getTicketName());
assertEquals("ticketSubName", savedTicketInformation.getTicketSubName());
assertEquals(4, savedTicketInformation.getTicketCount());
assertEquals(1000, savedTicketInformation.getTicketPrice());
assertEquals(subPayment, savedTicketInformation.getSubPayment());
}
}
1. @ExtendWith(MockitoExtension.class)
Mockito와 Junit5를 사용할 때 Spring에 의존하지 않고 test하는 어노테이션
2. @InjectMocks
Mock 객체를 @InjectMocks 어노테이션이 붙은 객체에 의존성 주입을 해주는 어노테이션
3. @Mock
가짜 객체
장점
1. 실제 Spring 서버를 실행하고 DB에 연결하는 과정에서 소요되는 시간을 절감할 수 있습니다.
2. Mock을 사용하여 원하는 계층에 관련된 독립적인 테스트를 진행할 수 있습니다.
참고
'백엔드 > Spring' 카테고리의 다른 글
jwt refresh token 을 Redis로 리팩토링하기 (0) | 2024.03.04 |
---|---|
[Spring] 서블릿과 스프링 MVC 패턴 (0) | 2023.07.14 |
[Spring] 디렉터리 패키지 구조 구성하는 방법 (0) | 2023.03.13 |
[Spring] JSP 대신 Thymeleaf를 사용하는 이유 (0) | 2022.08.22 |
[Spring] 상품 상세, 등록폼, 등록 처리, 상품 수정 (0) | 2022.07.28 |