코딩:개발일지

테스트 커버리지는 얼마나 확보해야 할까?

ZZJJing 2025. 5. 30. 17:57
반응형

테스트 커버리지란?

  • 정의: 전체 코드 중 테스트가 실행된 코드의 비율
  • 측정 단위: 퍼센트(%)로 표현
  • 목적: 코드 품질과 안정성 확보

적정 테스트 커버리지 수치

일반적인 권장사항

  • 최소 기준: 70% 이상
  • 권장 수준: 80-90%
  • 100%는 현실적이지 않음 (비용 대비 효과 낮음)

프로젝트별 기준

  • 금융/의료 시스템: 90% 이상
  • 일반 웹 애플리케이션: 80% 정도
  • 스타트업/MVP: 60-70%

커버리지 유형별 이해

Line Coverage (라인 커버리지)

public class Calculator {
    public int divide(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("Division by zero"); // 이 라인이 실행되었나?
        }
        return a / b; // 이 라인이 실행되었나?
    }
}

Branch Coverage (분기 커버리지)

// 모든 if-else 경로를 테스트했는가?
@Test
void testDivideByZero() {
    assertThrows(IllegalArgumentException.class, 
        () -> calculator.divide(10, 0)); // 예외 경로 테스트
}

@Test
void testNormalDivision() {
    assertEquals(5, calculator.divide(10, 2)); // 정상 경로 테스트
}

Java에서 커버리지 측정하기

JaCoCo 설정 (Maven)

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.8</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report</id>
            <phase>test</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>

JaCoCo 설정 (Gradle)

plugins {
    id 'jacoco'
}

jacoco {
    toolVersion = "0.8.8"
}

jacocoTestReport {
    reports {
        xml.required = false
        csv.required = false
        html.outputLocation = layout.buildDirectory.dir('jacocoHtml')
    }
}

효과적인 테스트 작성 방법

1. 핵심 비즈니스 로직 우선

@Service
public class OrderService {
    
    // 이런 핵심 로직은 반드시 테스트!
    public Order processOrder(OrderRequest request) {
        validateOrder(request);
        calculatePrice(request);
        return saveOrder(request);
    }
    
    @Test
    void shouldProcessValidOrder() {
        // Given
        OrderRequest request = new OrderRequest("product1", 2);
        
        // When
        Order result = orderService.processOrder(request);
        
        // Then
        assertThat(result.getStatus()).isEqualTo(OrderStatus.COMPLETED);
    }
}

2. 경계값 테스트

@Test
void testAgeValidation() {
    // 경계값들을 모두 테스트
    assertThrows(ValidationException.class, () -> validator.validate(17)); // 미성년자
    assertDoesNotThrow(() -> validator.validate(18)); // 경계값
    assertDoesNotThrow(() -> validator.validate(65)); // 정상값
}

3. 예외 상황 테스트

@Test
void shouldHandleEmptyDatabase() {
    // Given
    when(userRepository.findAll()).thenReturn(Collections.emptyList());
    
    // When & Then
    assertThrows(NoDataException.class, 
        () -> userService.getAllUsers());
}

커버리지 함정 주의사항

높은 수치 ≠ 좋은 테스트

// 나쁜 예: 커버리지만 높이는 테스트
@Test
void badTest() {
    userService.createUser("test");
    userService.deleteUser(1L);
    userService.updateUser(1L, "new");
    // 결과 검증 없음 - 의미없는 테스트
}

// 좋은 예: 의미있는 검증이 포함된 테스트
@Test
void shouldCreateUserSuccessfully() {
    // Given
    String username = "testUser";
    
    // When
    User result = userService.createUser(username);
    
    // Then
    assertThat(result.getUsername()).isEqualTo(username);
    assertThat(result.getId()).isNotNull();
}

팀별 커버리지 전략

개발 단계별 접근

  • 초기 개발: 핵심 로직 60%
  • 기능 완성: 전체 80%
  • 운영 준비: 중요 부분 90%

코드별 우선순위

  1. 비즈니스 로직: 90% 이상
  2. 유틸리티 클래스: 80% 이상
  3. 컨트롤러: 70% 이상
  4. 설정 클래스: 50% 정도

실무에서 자주 쓰는 도구들

1. IntelliJ IDEA 커버리지

  • Run with Coverage 기능 활용
  • 실시간으로 커버되지 않은 라인 확인 가능

2. SonarQube 연동

# GitHub Actions 예시
- name: SonarQube Scan
  run: ./gradlew sonarqube

3. 커버리지 품질 게이트

<!-- 80% 미만시 빌드 실패 -->
<execution>
    <id>check</id>
    <goals>
        <goal>check</goal>
    </goals>
    <configuration>
        <rules>
            <rule>
                <element>BUNDLE</element>
                <limits>
                    <limit>
                        <counter>LINE</counter>
                        <value>COVEREDRATIO</value>
                        <minimum>0.80</minimum>
                    </limit>
                </limits>
            </rule>
        </rules>
    </configuration>
</execution>

 

기억할 포인트

  • 수치보다 품질이 중요
  • 핵심 로직 먼저, 전체 커버리지는 나중에
  • 팀 상황에 맞는 현실적인 목표 설정
  • 지속적인 측정과 개선

체크리스트

  • [ ] 내가 작성한 코드의 핵심 로직은 테스트했는가?
  • [ ] 예외 상황도 고려했는가?
  • [ ] 테스트가 실제로 의미있는 검증을 하는가?
  • [ ] 커버리지 도구를 정기적으로 확인하는가?

테스트 커버리지는 목표가 아닌 수단

안정적이고 유지보수 가능한 코드를 만드는 것이 진짜 목표

 

728x90
반응형