[Java] 유틸리티 클래스를 테스트 커버리지 100% 만들기

Gyuyeon·2022년 5월 6일
0

Java

목록 보기
1/1

유틸리티 클래스를 테스트 커버리지 100% 만들기

유틸리티 클래스

게시판을 구현하는 도중 게시글이 작성된 시간을 변환하기 위해 아래와 같은 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%인것을 발견하였습니다...😱

상세 코드를 확인해 보니 원인은 아무래도 클래스 생성을 안하기 때문에 그런것 같았습니다.

해결법

1. 자동으로 생성되는 default 생성자로 인스턴스화 하기

abstract 클래스가 아니라면 가능하기는 하나 애초에 유틸리티 클래스를 인스턴스화 하는 것이 바람직하지 않다 생각하여 추천하지 않음.

2. private 접근 제어자의 생성자 만들기

Jacoco 0.8.0 부터 유틸리티 클래스에서 private 생성자가 있을 경우에는 Jacoco에서 테스트 커버리지 계산에 인스턴스 생성을 포함하지 않음.

3. 인터페이스화 하기

클래스를 인터페이스로 변환하는 방법인데 정적 변수가 없고 정적 메서드만 있는 지금의 경우에는 적합하지 않다고 판단.

결론

불필요하게 인스턴스를 생성하는 테스트를 만들 필요 없이(어짜피 abstract class 라서 바로 인스턴스화가 불가능하긴 하지만..) private 생성자를 만드는 것만으로 테스트 커버리지를 올릴 수 있었습니다! 😄

참고한 자료

1. https://spongeb0b.tistory.com/100
2. https://www.nerd.vision/post/jacoco-coverage-of-util-classes
profile
공부 중 기록하는 내용으로 혹시 잘못된 내용이 있을 시에는 알려 주시면 감사하겠습니다 😀

0개의 댓글