게시판을 구현하는 도중 게시글이 작성된 시간을 변환하기 위해 아래와 같은 TimeUtil 유틸리티 클래스
를 작성하였습니다.
public class TimeUtil {
public static String calculateTimeBeforeNow(LocalDateTime time) {
LocalDateTime now = LocalDateTime.now();
return getTimeBeforeFormat(time, now);
}
public static String calculateTimeBetween(LocalDateTime before, LocalDateTime after) {
return getTimeBeforeFormat(before, after);
}
private static String getTimeBeforeFormat(LocalDateTime time, LocalDateTime now) {
long second = ChronoUnit.SECONDS.between(time, now);
if(second < 60) {
return Long.toString(second) + "초 전";
}
long minute = ChronoUnit.MINUTES.between(time, now);
if(minute < 60) {
return Long.toString(minute)+ "분 전";
}
long hour = ChronoUnit.HOURS.between(time, now);
if(hour < 24) {
return Long.toString(hour)+ "시간 전";
}
long day = ChronoUnit.DAYS.between(time, now);
if(day < 30) {
return Long.toString(day)+ "일 전";
}
long month = ChronoUnit.MONTHS.between(time, now);
if(month < 12) {
return Long.toString(month)+ "달 전";
}
return Long.toString(ChronoUnit.YEARS.between(time, now)) + "년 전";
}
}
유틸리티 클래스란?
인스턴스 메서드와 인스턴스 변수를 일절 제공하지 않고, 정적 메서드와 변수만을 제공하는 클래스를 뜻한다.
클래스 본래의 목적인 '데이터와 데이터 처리를 위한 로직의 캡슐화'를 실행하는 것이 아닌, '비슷한 기능의 메서드와 상수를 모아서 캡슐화'한 것이 유틸리티 클래스이다.
최근 테스트의 중요성을 깨닫고 모든 코드에 대해 테스트 코드를 작성 / 테스트 커버리지 100% 달성을 목표로 하던 도중...
분명 모든 코드를 실행하는 테스트 코드를 작성했다고 생각 하던 도중, Jacoco Report에서 확인한 테스트 커버리지가 96%인것을 발견하였습니다...😱
상세 코드를 확인해 보니 원인은 아무래도 클래스 생성을 안하기 때문에 그런것 같았습니다.
abstract 클래스가 아니라면 가능하기는 하나 애초에 유틸리티 클래스를 인스턴스화 하는 것이 바람직하지 않다 생각하여 추천하지 않음.
Jacoco 0.8.0 부터 유틸리티 클래스에서 private 생성자가 있을 경우에는 Jacoco에서 테스트 커버리지 계산에 인스턴스 생성을 포함하지 않음.
클래스를 인터페이스로 변환하는 방법인데 정적 변수가 없고 정적 메서드만 있는 지금의 경우에는 적합하지 않다고 판단.
불필요하게 인스턴스를 생성하는 테스트를 만들 필요 없이(어짜피 abstract class 라서 바로 인스턴스화가 불가능하긴 하지만..) private 생성자를 만드는 것만으로 테스트 커버리지를 올릴 수 있었습니다! 😄
1. https://spongeb0b.tistory.com/100
2. https://www.nerd.vision/post/jacoco-coverage-of-util-classes