White-Box Testing: Branch/Condition, MC/DC, and Multiple Condition Coverage

1️⃣ Branch/Condition Testing
2️⃣ Modified Condition/Decision Coverage Testing
3️⃣ Multi-condition testing
학습 목표
오늘 강의에서는 화이트박스 테스팅 기법 중 커버리지 기반의 세 가지 기법을 다룬다.
첫째, 분기·조건 테스팅 기법 (Branch and Condition Testing) 을 이해하고 설명할 수 있어야 한다. 둘째, 변경조건·결정 테스팅 기법 (Modified Condition/Decision Coverage, MC/DC) 을 이해하고 설명할 수 있어야 한다. 셋째, 다중조건 테스팅 기법 (Multiple Condition Testing) 을 이해하고 설명할 수 있어야 한다.
세 기법 모두 현업에서 실제로 존재하는 화이트박스 테스팅 기법이다. 특히 MC/DC는 미국 FAA(연방항공청)의 항공 소프트웨어 안전 표준(DO-178B/C)에서 요구하는 기법으로, 높은 신뢰성이 요구되는 시스템에서 광범위하게 사용된다.
1️⃣ Branch/Condition Testing
분기/조건 테스팅 (Branch Condition Testing)
분기/조건 테스팅은 앞서 별개로 학습했던 분기 테스팅 (Branch Testing) 과 조건 테스팅 (Condition Testing) 을 하나로 합친 기법이다. 두 기법을 커버리지 기준으로 살펴보면 서로 겹치는 부분도 있지만, 한쪽이 다른 쪽을 완전히 포함하지 못하는 사례가 존재한다. 이러한 한계를 보완하기 위해 두 기법을 결합한 것이 분기/조건 테스팅이다.
정의는 다음과 같다. 전체 조건식 (분기문 전체) 이 True 한 번, False 한 번을 갖는 동시에, 각 개별 조건 (Individual Condition) 역시 True 한 번, False 한 번을 갖도록 테스트 케이스를 선정하여 테스트하는 기법이다.
장학생 선정 기능을 예제로 살펴보자. if ((평균 >= 90) && (과목수 >= 5)) 라는 구문에서, 마름모 전체가 하나의 전체 조건식 (Decision) 이자 하나의 분기가 된다. 이 분기는 Yes/No, 즉 True/False로 나뉜다. 그리고 if문 안의 평균 >= 90과 과목수 >= 5는 각각 개별 조건 (Individual Condition) 이며, 이 역시 각각 True/False를 가진다.
따라서 분기/조건 테스팅이 만족해야 할 항목은 다음과 같다.
전체 조건식의 True/False → 2가지
평균 >= 90의 True/False → 2가지과목수 >= 5의 True/False → 2가지
합계 총 6가지이며, 이 6가지를 모두 충족하는 테스트 케이스를 설계하는 것이 목표다.
분기/조건 커버리지 (Branch/Condition Coverage) 는 다음과 같이 계산한다.
테스트한 전체 조건 및 개별 조건의 T/F 수 ÷ 전체 조건 및 개별 조건의 T/F 수 × 100%
예를 들어 (95점, 6과목), (72점, 3과목) 두 케이스를 테스트하면, 첫 번째 케이스는 전체 조건식이 True이고 두 개별 조건 모두 True가 된다. 두 번째 케이스는 전체 조건식이 False이고 두 개별 조건 모두 False가 된다. 결과적으로 6가지 항목을 모두 커버하므로 분기/조건 커버리지 = 6/6 = 100% 가 된다.
📌한 가지 주의할 점이 있다. (72점, 3과목) 케이스에서 전체 조건식은 False이고 두 개별 조건 모두 False가 되어 커버리지 계산상 6/6이 성립하지만, 이는 개별 조건의 True/False가 전체 조건식의 True/False와 항상 독립적으로 관찰되는 것이 아님을 의미한다. 이것이 바로 분기/조건 테스팅의 한계이며, 이를 보완하기 위해 MC/DC가 등장하는 배경이 된다.
분기/조건 테스팅 (Branch Condition Testing); 등장 배경
분기/조건 테스팅이 왜 등장했는지 이해하려면, 먼저 기존 두 기법의 한계를 살펴야 한다.
분기 테스팅 (Branch Testing) 의 결과물은 분기 커버리지 (Branch Coverage) 이고, 조건 테스팅 (Condition Testing) 의 결과물은 조건 커버리지 (Condition Coverage) 이다. 이 둘은 어느 정도 중복되는 영역이 있지만, 분기 커버리지 100%가 조건 커버리지 100%를 보장하지 못하고, 반대로 조건 커버리지 100%가 분기 커버리지 100%를 보장하지 못하는 경우가 발생한다.
A AND B 라는 전체 조건식을 예시로 살펴보자.
분기 테스팅만 적용한 경우, 전체 조건식이 True 한 번, False 한 번 나오는 테스트 케이스를 설계한다. 예를 들어 A=True, B=False이면 전체 결과는 False, A=True, B=True이면 전체 결과는 True가 된다. 전체 조건식의 True/False가 모두 충족되어 분기 커버리지는 100%이다. 그러나 이 경우 개별 조건 (Individual Condition) A는 True/True만 존재하고 False가 한 번도 등장하지 않는다. 즉 조건 커버리지를 만족하지 못한다.
조건 테스팅만 적용한 경우, 개별 조건 A와 B 각각이 True/False를 한 번씩 가져야 한다. A=True, B=False 그리고 A=False, B=True로 설계하면 조건 커버리지는 100% 만족된다. 그러나 전체 조건식의 결과는 True AND False = False, False AND True = False로 모두 False가 된다. 전체 조건식 (분기) 의 True가 한 번도 나오지 않아 분기 커버리지를 만족하지 못한다.
이처럼 두 기법이 각각 서로의 커버리지를 보완하지 못하는 상황을 해결하기 위해 등장한 것이 분기/조건 테스팅 (Branch Condition Testing) 이다. 이 기법으로 테스트 케이스를 설계하면, 개별 조건 A=False, B=False 그리고 A=True, B=True로 구성할 수 있다. AND 연산 결과 전체 조건식은 False, True가 되어 분기 커버리지도 100%, 조건 커버리지도 100% 만족하는 단 두 개의 테스트 케이스가 완성된다.
이처럼 테스트 설계 기법들은 테스트 케이스 수는 줄이면서 커버리지는 높이는 방향으로 발전해왔다. 테스트에서는 항상 효율성 (Efficiency) 과 효과성 (Effectiveness) 을 함께 고려해야 하며, 단순히 테스트 케이스를 무작정 늘리는 것은 좋은 전략이 아니다.
임의의 프로그램에 대한 분기/조건 테스팅 적용 (1/2)
앞서 다른 기법에서도 사용했던 동일한 코드를 이번에는 분기/조건 테스팅 관점에서 분석해보자. 입력값은 X, Y, Z 세 가지이며, if문이 두 개 존재하고 각각의 if문 안에 개별 조건식들이 포함되어 있다.
이를 제어 흐름도 (Control Flow Graph) 로 표현하면 다음과 같이 구성된다.
목표는 분기/조건 커버리지 (Branch/Condition Coverage) 100% 를 만족하는 테스트 케이스를 설계하는 것이다. 총 12가지 항목을 모두 커버하는 테스트 케이스를 최소한의 수로 설계하는 것이 이번 예시의 핵심이다. 구체적인 테스트 케이스 도출은 다음 슬라이드에서 이어진다.
임의의 프로그램에 대한 분기/조건 테스팅 적용 (2/2)
목표는 모든 분기를 지나는 경로를 포함하면서 개별 조건의 True/False를 만족하는 최소한의 테스트 케이스를 도출하는 것이다. 앞서 확인했듯이 만족해야 할 항목은 총 12가지이다.
테스트 케이스 1: X=0, Y=0, Z=1
개별 조건1
X > 1→ 0 > 1이므로 False개별 조건2
Y == 1→ 0 == 1이므로 False분기1 전체
False AND False→ False개별 조건3
X == 2→ 0 == 2이므로 False개별 조건4
Z > 1→ 1 > 1이므로 False분기2 전체
False OR False→ False
테스트 케이스 2: X=2, Y=1, Z=6
개별 조건1
X > 1→ 2 > 1이므로 True개별 조건2
Y == 1→ 1 == 1이므로 True분기1 전체
True AND True→ True개별 조건3
X == 2→ 2 == 2이므로 True개별 조건4
Z > 1→ 6 > 1이므로 True분기2 전체
True OR True→ True
이 두 개의 테스트 케이스만으로 12가지 항목을 모두 커버하므로 분기/조건 커버리지 = 12/12 = 100% 가 달성된다.
이처럼 동일한 커버리지 목표를 달성하더라도 테스트 케이스를 어떻게 설계하느냐에 따라 케이스의 수가 크게 달라질 수 있다. 소프트웨어 테스팅에서는 항상 프로젝트의 시간과 비용 제약이 존재하므로, 테스트 케이스 수는 줄이면서 커버리지는 최대한 높이는 것이 핵심 목표이다.
이번 챕터에서는 분기 테스팅과 조건 테스팅을 결합한 분기/조건 테스팅 (Branch Condition Testing) 의 개념과 적용 예시를 살펴보았다. 그러나 이 기법 역시 한계가 존재하며, 관련 내용은 다음 기법인 MC/DC에서 이어진다.
2️⃣ Change Condition/Decision Testing
변경조건/결정 테스팅 (Modified Condition/Decision Coverage, MC/DC)
MC/DC 라는 이름은 다음과 같이 해석할 수 있다. Condition 은 앞서 배운 조건 테스팅의 개별 조건을, Decision 은 분기, 즉 전체 조건식을 의미한다. 그리고 Modified 는 기존 분기/조건 테스팅에 문제가 있어 이를 변경·보완했다는 의미이다.
기존 분기/조건 테스팅의 문제점은 다음과 같다. 하나의 분기문 안에는 여러 개별 조건이 존재하는데, 어떤 개별 조건의 True/False를 변경하더라도 전체 조건식의 결과에 아무런 영향을 주지 못하는 경우가 발생할 수 있다. 즉 커버리지 수치는 충족되지만 실질적으로 의미 없는 테스트 케이스가 포함될 수 있다는 것이다.
이를 해결하기 위해 등장한 것이 MC/DC이다. 정의는 다음과 같다. 각 개별 조건이 다른 조건에 영향을 받지 않고 독립적으로 작동하면서, 동시에 해당 개별 조건의 변화가 전체 조건식의 결과에 영향을 주도록 테스트 케이스를 선정하여 테스트하는 기법이다.
장학생 선정 예제 if ((평균 >= 90) && (과목수 >= 5)) 를 통해 살펴보자. 가능한 케이스는 총 4가지이다.
| 평균 >= 90 | 과목수 >= 5 | 장학생 선정 |
|---|---|---|
| True | True | True |
| True | False | False |
| False | True | False |
| False | False | False |
이 4가지를 모두 테스트하는 것은 효율적이지 않다. MC/DC는 이 중 의미 있는 케이스만을 추려낸다.
평균 조건의 독립적 영향 확인: 과목수를 True(6과목)로 고정한 상태에서 평균만 변경한다. (95점, 6과목) → 장학생 선정 True, (72점, 6과목) → 장학생 선정 False. 평균 조건의 변화가 전체 결과에 독립적으로 영향을 준다.
과목수 조건의 독립적 영향 확인: 평균을 True(95점)로 고정한 상태에서 과목수만 변경한다. (95점, 6과목) → 장학생 선정 True, (95점, 3과목) → 장학생 선정 False. 과목수 조건의 변화가 전체 결과에 독립적으로 영향을 준다.
결과적으로 선정되는 테스트 케이스는 (95점, 6과목), (95점, 3과목), (72점, 6과목) 세 가지이다. False/False 케이스가 제외되는 이유는, 해당 상태에서 어느 한 개별 조건을 True로 바꾸더라도 AND 연산에 의해 전체 결과가 여전히 False로 유지되기 때문이다. 전체 조건식의 결과에 영향을 주지 못하므로 MC/DC 조건을 만족하지 못한다.
MC/DC 커버리지 계산 공식은 다음과 같다.
MC/DC를 만족하는 개별 조건 수 ÷ 테스트가 실제 수행된 MC/DC 만족 전체 개별 조건 수 × 100%
위 예시에서는 평균과 과목수 두 개별 조건 모두 MC/DC 조건을 만족하므로 2/2 = 100% 가 된다.
분기/조건 테스팅 (Branch Condition Testing)의 문제점
분기/조건 테스팅이 100% 커버리지를 달성하더라도 개발자의 실수를 잡아내지 못하는 경우가 존재한다.
장학생 선정 기능 if ((평균 >= 90) && (과목수 >= 5)) 을 예로 들어보자. 개발자가 실수로 && 대신 || 를 입력했다고 가정한다. 분기/조건 테스팅 관점에서 (95점, 6과목), (72점, 3과목) 두 케이스를 테스트하면 전체 조건식이 True/False를 모두 충족하고 개별 조건도 True/False를 모두 충족하여 분기/조건 커버리지 100% 가 달성된다. 겉으로 보기에는 아무런 문제가 없는 것처럼 보인다.
그러나 실제 동작을 들여다보면 심각한 문제가 숨어있다. || 연산에서는 첫 번째 조건인 평균이 True가 되는 순간, 두 번째 조건인 과목수는 아예 평가조차 되지 않고 전체 결과가 True로 확정된다. 즉 (95점, 2과목) 이든 (95점, 0과목) 이든 관계없이 장학생으로 선정되어버리는 것이다. 평균과 과목수를 동시에 충족해야 한다는 본래의 요구사항이 완전히 무시되고 있음에도 불구하고, 분기/조건 테스팅은 이 결함을 발견하지 못한다.
이것이 분기/조건 테스팅의 핵심적인 한계이다. 개별 조건 각각의 True/False와 전체 조건식의 True/False는 확인하지만, 각 개별 조건이 전체 조건식의 결과에 실질적으로 독립적인 영향을 미치는지는 검증하지 못한다. 이 문제를 해결하기 위한 방법은 다음 슬라이드에서 이어진다.
📌프로그래밍에서 단락 평가 (Short-circuit Evaluation) 라고 부르는 현상과도 연관된다. || 연산에서 첫 번째 조건이 True이면 두 번째 조건은 평가되지 않고, && 연산에서 첫 번째 조건이 False이면 두 번째 조건은 평가되지 않는다. 분기/조건 테스팅이 이러한 결함을 탐지하지 못하는 것은 실제로 잘 알려진 한계이며, 이것이 MC/DC 등장의 핵심 동기이다.
분기/조건 테스팅 문제점의 해결 방안 (1) 모든 개별 조건을 테스트 케이스로 선정
가장 단순하고 직관적인 해결 방안은 가능한 모든 개별 조건의 조합을 테스트 케이스로 선정하는 것이다. 개별 조건이 2개인 장학생 선정 예제의 경우 True/False 조합이 총 4가지이므로 현실적으로 수행 가능하다. 이 4가지를 모두 테스트하면 && 가 || 로 잘못 작성된 개발자의 실수도 탐지할 수 있다. 오른쪽 표에서 볼 수 있듯이 || 연산에서는 (95점, 3과목), (72점, 6과목) 케이스의 전체 조건식 결과가 && 연산과 달리 True로 나타나 결함이 드러나기 때문이다.
그러나 이 방법은 현실적이지 않다. 개별 조건이 2개일 때는 2² = 4가지이지만, 개별 조건이 늘어날수록 테스트 케이스 수는 기하급수적으로 증가한다. 예를 들어 개별 조건이 20개라면 2²⁰ = 1,048,576가지의 테스트 케이스가 필요하다. 이는 시간과 비용 측면에서 테스트의 효율성과 적합성에 완전히 부합하지 않는 방안이다. 보다 현실적인 해결 방안은 다음에서 이어진다.
**📌**개별 조건 n개에 대한 모든 조합의 수는 2ⁿ으로, 이를 전수 테스팅 (Exhaustive Testing) 이라 부른다. 이것이 현실적으로 불가능하다는 점은 소프트웨어 테스팅의 기본 원칙 중 하나인 "완전한 테스팅은 불가능하다 (Exhaustive Testing is Impossible)" 와도 일치한다.
분기/조건 테스팅 문제점의 해결 방안 (2) 변경조건/결정 테스팅 (MC/DC) 적용
앞서 살펴본 전수 테스팅 방식의 한계를 극복하는 현실적인 해결책이 바로 변경조건/결정 테스팅 (Modified Condition/Decision Coverage, MC/DC) 이다. 이 기법은 다음 세 가지 조건을 동시에 만족해야 한다.
각 개별 조건은 다른 조건에 영향을 받지 않아야 한다. (독립성 Independence)
각 개별 조건의 True/False 변화가 전체 조건식의 결과에 영향을 주어야 한다. (유효성, Validity )
테스트 케이스 수를 줄일 수 있어야 한다. (효율성, Efficiency)
장학생 선정 예제 if ((평균 >= 90) && (과목수 >= 5)) 를 다시 살펴보자.
평균 조건의 독립적 영향 확인: 과목수를 6(True)으로 고정하고 평균만 95(True) → 72(False)로 변경하면 전체 조건식이 True → False로 바뀐다. 평균 조건이 독립적으로 전체 결과에 영향을 준다.
과목수 조건의 독립적 영향 확인: 평균을 95(True)로 고정하고 과목수만 6(True) → 3(False)으로 변경하면 전체 조건식이 True → False로 바뀐다. 과목수 조건 역시 독립적으로 전체 결과에 영향을 준다.
결과적으로 도출되는 테스트 케이스는 (95점, 6과목), (95점, 3과목), (72점, 6과목) 세 가지이며, 이것만으로 MC/DC 커버리지 2/2 = 100% 를 달성한다. 전수 테스팅의 4가지보다 1개 줄어든 수치이다. 더 나아가 개발자가 실수로 || 를 입력했을 경우, 이 3개의 테스트 케이스만으로도 결함을 탐지할 수 있다. || 연산에서는 (95점, 3과목)과 (72점, 6과목)의 전체 조건식 결과가 && 연산과 다르게 True로 나타나기 때문이다.
일반적으로 MC/DC 테스팅의 테스트 케이스 수 = 개별 조건 수 + 1 로 구할 수 있다. 장학생 선정 예제에서는 개별 조건이 2개이므로 2 + 1 = 3개의 테스트 케이스가 도출되며, 이는 실제 결과와 일치한다.
MC/DC 적용 예시 (1) AND 연산
if ((X > 1) AND (Y == 1)) 을 예시로 MC/DC를 적용해보자. 모든 조건을 고려하면 테스트 케이스는 총 4가지가 나온다. MC/DC는 이를 최소화하는 것이 목표이다.
개별 조건1(Individual Condition) X > 1 의 독립적 영향 확인 (TC1, TC3): Y == 1 을 True로 고정한 상태에서 X만 변경한다. X > 1이 True → False로 바뀌면 전체 조건식도 True → False로 바뀐다. 유효한 케이스이다.
개별 조건2(Individual Condition) Y == 1 의 독립적 영향 확인 (TC1, TC2): X > 1 을 True로 고정한 상태에서 Y만 변경한다. Y == 1이 True → False로 바뀌면 전체 조건식도 True → False로 바뀐다. 유효한 케이스이다.
두 과정에서 TC1이 중복되므로 하나를 제거하면 최종 테스트 케이스는 TC1, TC2, TC3 총 3개로 도출된다. 개별 조건 수 2 + 1 = 3 공식과도 일치한다.
| TC | X > 1 | Y == 1 | 전체 조건식 |
|---|---|---|---|
| TC1 | True | True | True |
| TC2 | True | False | False |
| TC3 | False | True | False |
4개에서 3개로 단 1개 줄어든 것이 사소해 보일 수 있다. 그러나 실제 프로그램에서 개별 조건이 3, 4, 5개 혹은 10개 이상으로 늘어날 경우, 전수 테스팅(Exhaustive Testing)의 2ⁿ개와 MC/DC의 N+1개 사이의 차이는 매우 크게 벌어진다. 예를 들어 개별 조건이 10개라면 전수 테스팅은 1,024개, MC/DC는 11개로 줄어든다. 이것이 MC/DC의 실질적인 가치이다.
MC/DC 적용 예시; 임의의 프로그램 (1/2)
앞서 분기/조건 테스팅 (Branch Condition Testing) 에서 사용했던 동일한 프로그램과 제어 흐름도 (Control Flow Graph) 를 그대로 활용한다.
이번 목표는 MC/DC 커버리지 (Modified Condition/Decision Coverage) 100% 를 만족하는 최소한의 테스트 케이스를 도출하는 것이다. 이를 위해 만족해야 할 조건은 다음과 같다.
분기1 (Decision 1)
(X > 1) AND (Y == 1)의 개별 조건 (Individual Condition) 각각이 독립적 (Independence) 으로 전체 조건식의 결과에 유효하게 (Effectiveness) 영향을 주어야 한다.분기2 (Decision 2)
(X == 2) OR (Z > 1)의 개별 조건 (Individual Condition) 각각도 동일한 조건을 만족해야 한다.전체 테스트 케이스 수는 효율적으로 (Efficiency) 최소화해야 한다.
구체적인 테스트 케이스 도출은 다음 슬라이드에서 이어진다.
MC/DC 적용 예시; 임의의 프로그램 (2/2)
MC/DC의 N+1 공식에 따라 분기1 (Decision 1) 과 분기2 (Decision 2) 각각 개별 조건 (Individual Condition) 이 2개씩이므로, 각 분기별로 최소 3개의 테스트 케이스가 필요하다.
도출된 테스트 케이스는 다음과 같다.
분기1의 MC/DC 검증:
개별 조건1
X > 1의 독립적 영향 확인 (TC1, TC3): 조건2를 True로 고정한 상태에서 조건1이 True → False로 바뀌면 분기1도 True → False로 바뀐다.개별 조건2
Y == 1의 독립적 영향 확인 (TC1, TC2): 조건1을 True로 고정한 상태에서 조건2가 True → False로 바뀌면 분기1도 True → False로 바뀐다.
분기2의 MC/DC 검증:
개별 조건3
X == 2의 독립적 영향 확인 (TC1, TC2): 조건4를 True/False 각각으로 보면, TC2에서 조건3이 True이고 조건4가 False일 때 분기2가 True, TC3에서 조건3이 False이고 조건4도 False일 때 분기2가 False로 조건3이 독립적으로 영향을 준다.개별 조건4
Z > 1의 독립적 영향 확인 (TC1, TC3): 조건3을 False로 고정한 상태에서 조건4가 True → False로 바뀌면 분기2도 True → False로 바뀐다.
이론적으로는 분기1과 분기2 각각 3개씩 총 6개의 테스트 케이스가 필요하지만, 단 3개의 테스트 케이스만으로 분기1과 분기2의 MC/DC 조건을 동시에 만족한다. 이는 매우 효율적 (Efficiency) 으로 설계된 테스트 케이스라 할 수 있다.
결과적으로 MC/DC 커버리지 = 4/4 = 100% 가 달성된다.
이로써 분기/조건 테스팅 (Branch Condition Testing) 의 문제점을 개선하기 위해 등장한 변경조건/결정 테스팅 (MC/DC) 의 개념과 적용 예시를 모두 살펴보았다.
3️⃣ Multi-condition testing
다중조건 테스팅 (Multiple Condition Testing)
다중조건 테스팅 (Multiple Condition Testing) 은 분기문 안에 있는 각 개별 조건 (Individual Condition) 의 모든 논리적 조합을 테스트 케이스로 선정하여 테스트하는 기법이다. 즉, 전수 테스팅 (Exhaustive Testing) 과 동일한 방식으로 개별 조건의 True/False 조합을 빠짐없이 모두 테스트한다.
장학생 선정 예제 if ((평균 >= 90) && (과목수 >= 5)) 를 보면, 개별 조건이 2개이므로 가능한 조합은 총 4가지이며 이를 모두 테스트한다.
| 평균 >= 90 | 과목수 >= 5 | 전체 조건식 |
|---|---|---|
| True | True | True |
| True | False | False |
| False | True | False |
| False | False | False |
다중조건 커버리지 (Multiple Condition Coverage) 계산 공식은 다음과 같다.
테스트한 개별 조건의 True/False 조합 수 ÷ 전체 개별 조건의 True/False 조합 수 × 100%
위 예시에서는 4/4 = 100% 가 된다.
다중조건 테스팅은 세 가지 기법 중 커버리지가 가장 높다는 장점이 있다. 그러나 개별 조건이 늘어날수록 테스트 케이스가 2ⁿ으로 기하급수적으로 증가하기 때문에, 시간·비용·노력이 가장 많이 소요된다는 단점이 있다.
이것이 MC/DC와 같이 커버리지와 효율성 (Efficiency) 을 균형 있게 추구하는 기법이 실무에서 더 널리 사용되는 이유이다.
다중조건 테스팅 (Multiple Condition Testing) 적용 예시; 임의의 프로그램
앞서 사용했던 동일한 프로그램에 다중조건 테스팅 (Multiple Condition Testing) 을 적용해보자. 목표는 다중조건 커버리지 (Multiple Condition Coverage) 100% 를 만족하는 테스트 케이스를 도출하는 것이다.
개별 조건 (Individual Condition) 은 총 4개이다.
개별 조건1:
X > 1개별 조건2:
Y == 1개별 조건3:
X == 2개별 조건4:
Z > 1
4개의 개별 조건에 대해 True/False의 모든 논리적 조합을 테스트해야 하므로 테스트 케이스는 2⁴ = 16개가 된다.
예를 들어 TC01은 X=0, Y=0, Z=1을 입력하면 4개의 개별 조건이 모두 False가 되고, TC16은 X=2, Y=1, Z=6을 입력하면 모두 True가 된다.
다중조건 커버리지 = 16/16 = 100% 가 달성된다. 그러나 이를 위해 16개의 테스트 케이스를 모두 수행해야 하므로 앞서 살펴본 분기/조건 테스팅 (Branch Condition Testing) 의 12개, MC/DC의 3개와 비교했을 때 가장 많은 시간과 비용, 노력이 소요된다.
다중조건 테스팅 (Multiple Condition Testing); 테스트 케이스 수와 커버리지의 관계
다중조건 테스팅 (Multiple Condition Testing) 은 분기문 안의 각 개별 조건 (Individual Condition) 의 모든 논리적 조합을 테스트 케이스로 선정하는 방법이므로, 커버리지 100% 달성에 필요한 최소 테스트 케이스 수는 2ⁿ 이 된다. 여기서 N은 개별 조건의 수이다.
지금까지 학습한 화이트박스 테스팅 (White-box Testing) 의 커버리지 기법들을 커버리지 크기 순으로 정리하면 다음과 같다.
| 기법 | 커버리지 크기 | 최소 테스트 케이스 수 |
|---|---|---|
| 함수 테스팅 (Function Testing) | 가장 작음 | - |
| 문장 테스팅 (Statement Testing) | ↑ | - |
| 분기/조건 테스팅 (Branch Condition Testing) | ↑ | - |
| 변경조건/결정 테스팅 (MC/DC) | ↑ | N + 1 |
| 다중조건 테스팅 (Multiple Condition Testing) | 가장 큼 | 2ⁿ |
실무에서는 가장 현실적인 균형점으로 MC/DC 를 최대 기준으로 활용하는 경우가 많다. 특히 항공, 의료 등 높은 신뢰성이 요구되는 시스템에서는 MC/DC가 표준으로 채택된다. 품질 요구사항이 상대적으로 낮은 시스템에서는 분기/조건 커버리지 (Branch Condition Coverage) 수준을 적용하기도 한다. 수업에서는 개별 조건이 2~4개인 작은 예제로 학습했지만, 실무에서는 개별 조건의 수가 훨씬 많아 테스트 케이스의 규모도 그에 비례하여 커진다는 점을 반드시 염두에 두어야 한다.
화이트박스 테스트 설계 기법별 커버리지 비교
지금까지 학습한 기법들을 동일한 예제 if ((A) AND (B)) 를 기준으로 최소 테스트 케이스 수와 커버리지를 비교해보자.
분기 테스팅 (Branch Testing): 전체 조건식이 True/False를 한 번씩 갖는 케이스를 찾는다. TC3과 TC4를 통해 분기 커버리지 (Branch Coverage) 100% 를 만족한다. 최소 2개의 테스트 케이스가 필요하다.
조건 테스팅 (Condition Testing): 각 개별 조건 (Individual Condition) A와 B가 각각 True/False를 한 번씩 갖는 케이스를 찾는다. TC2와 TC3을 통해 조건 커버리지 (Condition Coverage) 100% 를 만족한다. 최소 2개의 테스트 케이스가 필요하다.
분기/조건 테스팅 (Branch Condition Testing): 개별 조건 A, B 각각의 True/False와 전체 조건식의 True/False를 동시에 만족하는 케이스를 찾는다. TC1과 TC4를 통해 분기/조건 커버리지 (Branch Condition Coverage) 100% 를 만족한다. 최소 2개의 테스트 케이스가 필요하다.
변경조건/결정 테스팅 (MC/DC): 개별 조건 수 N + 1 공식에 따라 TC1, TC2, TC3 총 3개의 테스트 케이스로 MC/DC 커버리지 100% 를 만족한다.
다중조건 테스팅 (Multiple Condition Testing): 모든 논리적 조합을 테스트해야 하므로 TC1, TC2, TC3, TC4 총 4개 (2²) 의 테스트 케이스가 필요하며, 이를 통해 다중조건 커버리지 (Multiple Condition Coverage) 100% 를 만족한다.
이를 정리하면 커버리지가 높아질수록 테스트 케이스의 수도 증가하는 것을 확인할 수 있다. 특히 다중조건 테스팅 (Multiple Condition Testing) 은 개별 조건이 늘어날수록 테스트 케이스가 2ⁿ으로 기하급수적으로 증가하기 때문에, 실무에서는 커버리지와 효율성 (Efficiency) 의 균형을 고려한 적절한 기법을 선택하는 것이 중요하다.
기본 경로 테스팅 (Basic Path Testing)
기본 경로 테스팅 (Basic Path Testing) 은 화이트박스 테스팅 (White-box Testing) 기법 중 하나로, 프로그램의 기본 경로 (Basic Path) 들을 실행할 수 있는 테스트 케이스를 선정하여 테스트하는 방법이다. 이때 기본 경로를 선정하기 위해 순환 복잡도 (Cyclomatic Complexity, CC) 를 활용한다. 순환 복잡도는 맥케이브 (McCabe) 라는 학자에 의해 고안된 개념이다.
프로그램을 흐름 그래프 (Flow Graph) 형태로 표현하면 다음과 같은 요소들로 구성된다.
노드 (Node): 명령문을 나타낸다.
엣지 (Edge): 노드 간의 흐름을 나타낸다.
단정 노드 (Predicate Node): 반복문이나 선택문 (if문) 과 같이 분기가 발생하는 노드이다.
영역 (Region): 엣지와 노드로 닫혀진 영역으로 R1, R2, R3 등으로 표시된다.
슬라이드의 예시를 보면 노드 2, 3이 R1 영역을 형성하며 반복 구조를 이루고 있고, 노드 5에서 선택문에 의해 노드 6 또는 노드 7로 분기되는 구조가 표현되어 있다.
순환 복잡도 (CC) 를 구하는 공식은 세 가지가 있으며, 모두 동일한 결과를 도출한다.
| 공식 | 계산 | 결과 |
|---|---|---|
| CC = R (영역 수) | R = 3 | 3 |
| CC = E - N + 2 (엣지 수 - 노드 수 + 2) | 9 - 8 + 2 | 3 |
| CC = P + 1 (단정 노드 수 + 1) | 2 + 1 | 3 |
계산 결과 순환 복잡도가 3이므로, 최소 3개 이상의 독립적인 경로 (Independent Path) 를 테스트하면 프로그램의 기본 경로를 모두 테스트할 수 있다.
기본 경로 테스팅 (Basic Path Testing); 기본 경로와 커버리지
앞서 순환 복잡도 (Cyclomatic Complexity) CC = 3 을 통해 최소 3개의 독립적인 경로 (Independent Path) 가 필요함을 확인했다. 흐름 그래프 (Flow Graph) 에서 도출되는 기본 경로 (Basic Path) 는 다음 3가지이다.
경로1: 1 - 2 - 3 - 2 - 4 - 5 - 6 - 8
경로2: 1 - 2 - 3 - 2 - 4 - 5 - 7 - 8
경로3: 1 - 2 - 4 - 5 - 6 - 8
기본 경로 커버리지 (Basic Path Coverage) 계산 공식은 다음과 같다.
테스트한 기본 경로 수 ÷ 전체 기본 경로 수 × 100%
전체 기본 경로가 3개인 상황에서 경로1만 테스트했다면 1/3 = 약 33.33% 의 커버리지를 갖게 된다. 3개의 경로를 모두 테스트해야 비로소 기본 경로 커버리지 100% 를 달성할 수 있다.




