서론
본 포스팅은 아래의 인강을 듣고, 추가 공부가 필요한 내용들을 포함하여 정리한 포스팅입니다.
private method를 테스트해야 하는가
강의에서는, private 메서드를 테스트할 필요가 없으며, private 메서드를 테스트 고려해야 할 때를 객체를 분리해야하는 시점인가? 라는 질문을 던져보라고 하였다.
아래의 코드는, 다음 상품번호를 생성해주는 ProductService에서 발췌한 private 메서드 부분이다.
private String createNextProductNumber() {
String latestProductNumber = productRepository.findLatestProductNumber();
if (latestProductNumber == null) {
return "001";
}
int latestProductNumberInt = Integer.parseInt(latestProductNumber);
int nextProductNumberInt = latestProductNumberInt + 1;
return String.format("%03d", nextProductNumberInt);
}
private 메서드 부분을 새로운 Component 객체로 만들어, 새로운 객체의 공개 api(public)으로 만들어 책임 분리를 시켜서
해당 메서드를 테스트할 수 있긴 하다.
@Component
@RequiredArgsConstructor
public class ProductNumberFactory {
private final ProductRepository productRepository;
public String createNextProductNumber() {
String latestProductNumber = productRepository.findLatestProductNumber();
if (latestProductNumber == null) {
return "001";
}
int latestProductNumberInt = Integer.parseInt(latestProductNumber);
int nextProductNumberInt = latestProductNumberInt + 1;
return String.format("%03d", nextProductNumberInt);
}
}
우선, 해당 private 메서드가 클래스 내부에서 한 번도 사용이 되지 않았을 리가 없다. 해당 private 메서드는 클래스 내부에서 다른 테스트 안에 포함되어 항상 테스트가 가능했고, 가능할 것이다. 그렇게 짜여지지 않았다면 올바른 코드를 작성하지 않았다는 소리다. 그것을 아래 Justin Woo 님은 당신의 코드에 냄새가 난다고 서술하였다.
정말 private 메서드를 테스트할 욕구가 강하게 들거나, 해야 하는 상황이라면 무언가 설계가 잘못되었다는 신호로, 객체 분리의 신호로 받아들여 하나의 public 메서드 안에서 하는 일이 많지는 않은지, 객체가 가지는 로직이 많지 않은지 점검하여 private이라는 내부의 작은 기능을 별도의 객체로 위임을 해서 테스트를 단독으로 수행할 수 있도록 한다면 좋은 설계가 될 수 있을 것이다.
References
옛날 글이지만(14년도) 너무 좋은 개인 의견과 자료 제시해주신 Justin Woo님의 글을 정리해보았다.
출처 : https://justinchronicles.net/ko/2014/07/14/dont-do-testing-private-methods/
테스트 코드 공부를 진행하면서 접근제어자가 어떤 것이든 테스트를 해야하지 않나?? 라는 생각을 하고 있었다.
찾아보니 private 메서드는 우선 Mocking이 불가능하다. 테스트를 할 경우 보통 인터페이스를 통해 Mocking을 한 후 진행하는데, private 메서드는 인터페이스에 노출되어 있지 않기 때문이다.
private 메서드를 테스트해야 한다면, 또는 바꿀 때 마다 테스트 코드를 다시 짜야한다면, 리팩토링에 있어 큰 장애물이 될 것이다. 코드를 개선시키기 위해 해야 하는 일의 양이 private 메서드를 바꾸기 위해 필요한 일의 양이 되어버린다. 결국 이 모든 부정적인 과정들은 코드를 리팩토링하는 것을 주저하게 만든다.
관련 포스팅
테스트 코드를 작성하는 이유 - TestCode (1)
JUnit 5를 사용한 Java 단위 테스트 - TestCode (3)
통합 테스트(Integration Test) - TestCode(6)
@AfterEach, @BeforeEach - TestCode(7)
Mock / Test Double - TestCode (8)
더 좋은 테스트 작성하기(1) - TestCode(9)
더 좋은 테스트 코드 작성하기 2 - Test Fixture 구성하기 / TestCode(10)
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!