분기 테스팅

DoTheTest·2025년 8월 12일
0

테스트 지식

목록 보기
20/24

소프트웨어 개발에서 테스트는 코드의 신뢰성을 보장하는 필수적인 과정입니다. 하지만 단순히 코드가 실행되는 것만 확인하는 것으로는 충분하지 않습니다. 코드 속에 숨어있는 수많은 '갈림길', 즉 조건문들이 만들어내는 모든 논리적 경로를 제대로 검증해야만 진정한 안정성을 확보할 수 있습니다.

이러한 논리적 흐름의 허점을 찾아내는 가장 효과적인 화이트박스 테스트 기법 중 하나가 바로 분기 테스팅(Branch Testing)입니다.

1. 분기 테스팅(Branch Testing)이란 무엇인가?

분기 테스팅은 소스 코드의 모든 분기(Branch) 또는 결정(Decision) 지점의 결과가 참(True)과 거짓(False) 양쪽 모두 최소 한 번 이상 실행되도록 테스트 케이스를 설계하는 기법입니다.

  • 목표: 분기 커버리지(Branch Coverage) 100%를 달성하는 것.
  • 분기(결정) 지점이란? 코드의 실행 흐름을 둘 이상으로 나누는 모든 지점을 의미합니다. 여기에는 if/else, switch, for/while과 같은 루프문, 삼항 연산자(? :)가 모두 포함됩니다. C/Java/Python 등 많은 언어의 논리 연산자(&&, ||)에서 나타나는 단락 평가(Short-circuit Evaluation) 역시 암묵적인 분기를 만들어냅니다.
  • 비유 (갈림길 탐험): 분기 테스팅은 지도 위의 모든 '갈림길'에서 왼쪽 길과 오른쪽 길 양쪽 모두로 한 번씩 가보는 것과 같습니다. 어느 한쪽 길이라도 가보지 않았다면, 그 길 끝에 무엇이 있는지 결코 알 수 없습니다.

2. 분기 테스팅 실전 예제

if/else 구문은 분기 테스팅의 가장 대표적인 예시입니다.

// DiscountCalculator.java
public double applyDiscount(double price) {
    if (price >= 10000) {      // 결정 지점
        price = price * 0.9;
    }
    return price;
}

분기 커버리지 100%를 달성하기 위해서는 if문의 결과가 True가 되는 경로와 False가 되는 경로를 모두 테스트해야 합니다.

  • TC1 (True 경로): applyDiscount(10000.0)
  • TC2 (False 경로): applyDiscount(5000.0)

루프(Loop)에서의 분기

for, while과 같은 루프문도 내부적으로는 반복을 계속할지(True) 멈출지(False)를 결정하는 분기를 포함합니다.

public int sum(List<Integer> numbers) {
    int total = 0;
    for (Integer num : numbers) { // 루프 진입 결정
        total += num;
    }
    return total;
}

분기 커버리지를 충족하려면,

  • TC1 (True 경로): 루프에 최소 한 번 이상 진입하는 경우 (예: List.of(1, 2, 3))
  • TC2 (False 경로): 루프에 한 번도 진입하지 않고 바로 종료되는 경우 (예: 빈 리스트 List.of())
    두 가지 케이스를 모두 테스트해야 합니다. 이는 흔히 발생하는 '0, 1, N' 반복 오류를 잡는 데 도움이 됩니다.

💡 분기 테스팅을 위한 체크리스트

  • 모든 if/else 문의 true/false 경로를 테스트했는가?
  • 모든 switch 문의 casedefault를 테스트했는가?
  • 모든 삼항 연산자의 true/false 결과를 테스트했는가?
  • 모든 루프의 진입(1회 이상 반복)과 탈출(0회 반복) 경로를 테스트했는가?

3. 분기 커버리지의 중요성

분기 커버리지는 단순히 코드 라인을 실행해보는 구문 커버리지(Statement Coverage)보다 훨씬 강력한 척도입니다. 일반적으로 잘 구조화된 코드에서 분기 커버리지 100%는 구문 커버리지 100%를 포함(Subsume)합니다. 모든 갈림길의 양쪽을 다 가봤다면, 당연히 그 길들도 모두 밟아봤을 것이기 때문입니다.

4. 분기 테스팅의 한계: 복합 조건의 함정

분기 테스팅은 매우 강력하지만, 이것 역시 완벽하지는 않습니다. if문 안의 조건이 복잡해지면 맹점이 드러납니다.

public boolean isEligible(int age, boolean hasLicense) {
    if (age >= 19 && hasLicense) { // 결정 지점
        return true;
    }
    return false;
}
  • TC1: isEligible(20, true)if문 결과: True
  • TC2: isEligible(18, true)if문 결과: False

이 두 테스트만으로 분기 커버리지는 100%입니다. 하지만 우리는 여전히 '성인이지만 면허가 없는 경우'(isEligible(20, false))를 테스트하지 않았습니다! 만약 개발자가 실수로 && (AND)를 || (OR)로 잘못 코딩했다면, 우리의 분기 테스트는 이 심각한 결함을 발견하지 못합니다.

분기 테스팅은 결정 지점의 '최종 결과'에만 집중할 뿐, 그 결과를 만들어내는 '내부 조건들의 조합'까지는 들여다보지 못합니다.

5. 결론: 더 깊은 신뢰를 향한 중요한 발걸음

분기 테스팅은 코드의 모든 논리적 갈림길을 최소 한 번씩은 점검함으로써, 단순한 구문 테스트만으로는 발견할 수 없는 수많은 결함을 찾아냅니다. 대부분의 코드 커버리지 도구는 분기 커버리지를 중요한 지표로 제공하며, 많은 성숙한 개발팀은 분기 커버리지를 핵심 품질 지표로 삼습니다.

물론, 높은 커버리지 숫자가 테스트의 품질을 보장하지는 않습니다. 결과를 제대로 검증하는 어설션(Assertion)의 품질이 훨씬 더 중요합니다.

하지만 복합 조건문이 많은 코드에서는 분기 테스팅만으로 충분하지 않을 수 있습니다. 더 높은 수준의 신뢰도를 위해서는, 복합 조건문의 내부를 더욱 정밀하게 검증하는 조건 테스팅(Condition Testing)과 같은 다음 단계의 기법들을 탐험해볼 필요가 있습니다.


`

0개의 댓글