결정 커버리지 (Decision Coverage)

결정 커버리지는 프로그램의 모든 결정 포인트(조건문)에서 전체 조건식이 최소한 한 번씩 참(True)과 거짓(False)의 결과를 가지도록 테스트하는 방법이다.
이는 브랜치 커버리지(Branch Coverage)라고도 불린다.

간단한 예제:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class LoanApproval {
    public boolean approveLoan(double income, double creditScore) {
        if (income >= 50000) {
            if (creditScore >= 700) {
                return true;
            }
            return false;
        }
        return false;
    }
}

이 코드의 결정 커버리지를 100% 달성하기 위해서는 다음과 같은 테스트 케이스가 필요하다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Test
void testLoanApproval() {
    LoanApproval loanApproval = new LoanApproval();
    
    // 케이스 1: 두 조건 모두 true
    assertTrue(loanApproval.approveLoan(60000, 750));
    
    // 케이스 2: 첫 번째 조건 true, 두 번째 조건 false
    assertFalse(loanApproval.approveLoan(60000, 650));
    
    // 케이스 3: 첫 번째 조건 false
    assertFalse(loanApproval.approveLoan(40000, 750));
}

결정 커버리지를 계산하는 방법

1
2
3
4
5
6
7
8
9
결정 커버리지 = (테스트된 결정 결과의 수) / (가능한 총 결정 결과의 수) × 100%

예를 들어, 위의 LoanApproval 예제에서:
- 총 결정 포인트: 2개 (income 체크, creditScore 체크)
- 각 결정당 가능한 결과: 2개 (true/false)
- 총 가능한 결정 결과의 수: 4
- 테스트된 결정 결과의 수: 4

따라서, 결정 커버리지 = (4/4) × 100% = 100%

주의해야 할 중요한 포인트

  1. 중첩된 조건문의 처리:

    1
    2
    3
    4
    5
    6
    7
    8
    
    public boolean validateUser(String username, String password) {
        if (username != null) {
            if (password != null) {
                return true;
            }
        }
        return false;
    }
    

    이런 중첩된 조건문의 경우, 모든 가능한 경로를 테스트해야 한다:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    @Test
    void testUserValidation() {
        // 모든 조건 true
        assertTrue(validateUser("user", "pass"));
    
        // 첫 번째 조건 true, 두 번째 조건 false
        assertFalse(validateUser("user", null));
    
        // 첫 번째 조건 false
        assertFalse(validateUser(null, "pass"));
    }
    
  2. 복합 조건문의 처리:

    1
    2
    3
    4
    5
    6
    
    public boolean isEligible(int age, boolean hasLicense) {
        if (age >= 18 && hasLicense) {
            return true;
        }
        return false;
    }
    

    복합 조건문의 경우, 전체 조건식의 결과가 true와 false가 되는 경우만 테스트하면 된다:

    1
    2
    3
    4
    5
    6
    7
    8
    
    @Test
    void testEligibility() {
        // 전체 조건 true
        assertTrue(isEligible(20, true));
    
        // 전체 조건 false (여러 케이스 중 하나만 있어도 됨)
        assertFalse(isEligible(16, true));
    }
    

주요 특징

  1. 전체 조건식 중심: 개별 조건이 아닌 전체 조건식의 결과에 초점을 맞춘다.
  2. 최소 테스트 케이스: 개별 조건식의 수와 관계없이 최소 2개의 테스트 케이스로 충족이 가능하다.
  3. 구문 커버리지 보장: 100% 결정 커버리지를 달성하면 100% 구문 커버리지도 자동으로 달성된다.

장점

  1. 구문 커버리지보다 강력: 더 철저한 테스트가 가능하다.
  2. 분기 테스트: 모든 분기문을 테스트할 수 있다.
  3. 예외 상황 발견: 구문 커버리지로는 발견하기 어려운 예외 상황을 찾아낼 수 있다.

한계점

  1. 복잡한 조건문 처리: 여러 개의 조건이 결합된 복잡한 조건문의 경우, 모든 가능한 조합을 테스트하지 못할 수 있다.
  2. 개별 조건 무시: 전체 조건식의 결과만을 고려하기 때문에 개별 조건의 영향을 세밀하게 테스트하지 못할 수 있다.

적용 방법

  1. 모든 조건문 식별: 프로그램 내의 모든 조건문(if, switch 등)을 식별한다.
  2. 테스트 케이스 설계: 각 조건문이 참과 거짓 결과를 모두 가지도록 테스트 케이스를 설계한다.
  3. 테스트 실행: 설계된 테스트 케이스를 실행하고 결과를 확인한다.
  4. 커버리지 측정: 전체 조건문 중 테스트된 조건문의 비율을 계산한다.

결정 커버리지는 구조적 테스팅에서 중요한 역할을 하며, 특히 분기문이 많은 복잡한 로직을 테스트하는 데 효과적이다.
하지만 더 철저한 테스트를 위해서는 조건 커버리지나 MC/DC(Modified Condition/Decision Coverage)와 같은 더 높은 수준의 커버리지 기법과 함께 사용하는 것이 좋다.


참고 및 출처