1. 목표
만일 구현하고자 하는 기능이 책 등록을 하면 이메일을 보내는 기능이고 이메일을 보내는 것은 내가 구현하는 부분이 아니라면 그림처럼 MailSender를 이용하여 테스트할 수 있다.
2. 필요한 클래스 생성
Mail 클래스 생성
public class Mail {
public boolean sendMail() {
//기능
return true;
}
}
MailSender 인터페이스 생성
public interface MailSender {
boolean send();
}
MailSenderStub 클래스 생성
import org.springframework.stereotype.Component;
@Component
public class MailSenderStub implements MailSender {
@Override
public boolean send() {
// TODO Auto-generated method stub
return false;
}
}
MailSenderAdapter 클래스 생성
public class MailSenderAdapter implements MailSender {
//private Mail mail;
//public MailSenderAdapter() {
// this.mail = new Mail();
//}
@Override
public boolean send() {
return true;
}
}
BookService에 코드 추가
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository bookRepository;
// 추가하는 부분
private final MailSender mailSender;
// 1. 책등록
@Transactional(rollbackFor = RuntimeException.class)
public BookRespDto 책등록하기(BookSaveReqDto dto) {
Book bookPS = bookRepository.save(dto.toEntity());
// if절 추가하면됨!!
if(bookPS != null) {
if(!mailSender.send()) {
throw new RuntimeException("메일이 전송되지 않았습니다.");
}
}
return new BookRespDto().toDto(bookPS);
}
3. 메일 기능이 구현이 되었다면
MailSenderAdapter에 @Component 어노테이션을 달고 Stub에 있는 @Component를 지워야한다. 두 개를 쓰면 안되는 이유는 스프링은 IoC 컨테이너를 싱클톤으로 관리하기 때문에 같은 타입을 올릴 수 없어서이다.
BookServiceTest에 BookService를 메모리에 띄워야 되는데 BookService는 BookRepository와 MailSender에 의존하고 있다.
MailSender는 Stub를 사용하면 쉽게 해결할 수 있다.
그럼 BookRepository는? 이것 역시 Respository를 테스트할 때 했던 것처럼 위에 @DataJpaTest를 붙이고 DI해서 사용하면 되는 것이 아닌가? 하는 생각에 한번 해보았다.
@Test
public void 책등록하기_테스트() {
// given
BookSaveReqDto dto = new BookSaveReqDto();
dto.setTitle("junit lecture");
dto.setAuthor("momo");
// stub
MailSenderStub mailSenderStub = new MailSenderStub();
// when
BookService bookService = new BookService(bookRepository, mailSenderStub);
BookRespDto bookRespDto = bookService.책등록하기(dto);
// then
assertEquals(dto.getTitle(), bookRespDto.getTitle());
assertEquals(dto.getAuthor(), bookRespDto.getAuthor());
}
이렇게 해보니 잘 된다. 그럼 이대로 괜찮은가? 아니다. 이대로 하면 Service만 테스트하고 싶은데 repository 레이어가 함께 테스트 된다. 이건 어떻게 해결해야 하는가. 이것도 mailStub처럼 가짜 repository를 만들어서 해결할 수 있다. 이것을 하려면 Mockito 라는 가짜 객체를 보관하는 환경이 필요하다.