# 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

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/833bc7fe-b07f-46b6-82dc-ecc96c7512b8.png align="center")

### 분기/조건 테스팅 (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%를 보장하지 못하는 경우가 발생한다.

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/b2663c1d-3f67-41f9-af64-0423e4402ab8.png align="center")

`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문 안에 개별 조건식들이 포함되어 있다.

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/25005225-b00d-4b5b-9974-d632394d24fc.png align="center")

이를 **제어 흐름도 (Control Flow Graph)** 로 표현하면 다음과 같이 구성된다.

목표는 **분기/조건 커버리지 (Branch/Condition Coverage) 100%** 를 만족하는 테스트 케이스를 설계하는 것이다. 총 **12가지 항목**을 모두 커버하는 테스트 케이스를 최소한의 수로 설계하는 것이 이번 예시의 핵심이다. 구체적인 테스트 케이스 도출은 다음 슬라이드에서 이어진다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/33bb5691-f168-4388-a4cd-12ca3e734127.png align="center")

#### 임의의 프로그램에 대한 분기/조건 테스팅 적용 (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에서 이어진다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/66f9bf61-9a1c-49eb-ae7a-04755bcae8cb.png align="center")

# 2️⃣ Change Condition/Decision Testing

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/c48d8953-c679-4dfa-aff7-3e2853680c19.png align="center")

### 변경조건/결정 테스팅 (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%** 가 된다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/85b056f6-c76a-4387-9ec8-5c665f788fdf.png align="center")

### 분기/조건 테스팅 (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 등장의 핵심 동기이다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/3145c84d-40a6-4f0c-90f3-f3b236e57e28.png align="center")

### 분기/조건 테스팅 문제점의 해결 방안 (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)"** 와도 일치한다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/09c2ed77-b851-4d12-bf28-d44c533d1f6b.png align="center")

### 분기/조건 테스팅 문제점의 해결 방안 (2) 변경조건/결정 테스팅 (MC/DC) 적용

앞서 살펴본 전수 테스팅 방식의 한계를 극복하는 현실적인 해결책이 바로 **변경조건/결정 테스팅 (Modified Condition/Decision Coverage, MC/DC)** 이다. 이 기법은 다음 세 가지 조건을 동시에 만족해야 한다.

1.  각 개별 조건은 다른 조건에 영향을 받지 않아야 한다. (**독립성** Independence)
    
2.  각 개별 조건의 True/False 변화가 전체 조건식의 결과에 영향을 주어야 한다. (**유효성,** Validity )
    
3.  테스트 케이스 수를 줄일 수 있어야 한다. (**효율성,** 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개**의 테스트 케이스가 도출되며, 이는 실제 결과와 일치한다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/6c1d3881-819f-4584-8ffb-1cb950e6b4c6.png align="center")

### 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) 를 그대로 활용한다.

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/09d0053d-a976-42f6-aad9-48fa5a3db327.png align="center")

이번 목표는 **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개의 테스트 케이스가 필요하다.

도출된 테스트 케이스는 다음과 같다.

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/14b20788-a098-49ff-abb4-9d207fdf75e7.png align="center")

**분기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)** 의 개념과 적용 예시를 모두 살펴보았다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/2752c883-f46d-41e3-a4c9-a287a12e4104.png align="center")

# 3️⃣ Multi-condition testing

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/341daeee-7f25-48c8-9f3b-d0bab51e7183.png align="center")

### 다중조건 테스팅 (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) 을 균형 있게 추구하는 기법이 실무에서 더 널리 사용되는 이유이다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/d8265465-7344-41bb-90e3-92240804b5df.png align="center")

### 다중조건 테스팅 (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`
    

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/2f365ea5-cef5-4979-932d-53203d503a52.png align="center")

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개와 비교했을 때 가장 많은 시간과 비용, 노력이 소요된다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/dff73cfa-cffe-4292-9235-a0842b8af98d.png align="center")

### 다중조건 테스팅 (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개인 작은 예제로 학습했지만, 실무에서는 개별 조건의 수가 훨씬 많아 테스트 케이스의 규모도 그에 비례하여 커진다는 점을 반드시 염두에 두어야 한다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/51f6ce66-5462-498d-8685-a5b7b558ac25.png align="center")

### 화이트박스 테스트 설계 기법별 커버리지 비교

지금까지 학습한 기법들을 동일한 예제 `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) 의 균형을 고려한 적절한 기법을 선택하는 것이 중요하다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/67376b1b-8ace-4c68-90ed-7179ef8c45d4.png align="center")

### 기본 경로 테스팅 (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)** 를 테스트하면 프로그램의 기본 경로를 모두 테스트할 수 있다.

* * *

![](https://cdn.hashnode.com/uploads/covers/649932cadd0a52758cdbdeb5/847c4e62-4d52-452a-bbe7-690a7b2a492d.png align="center")

### 기본 경로 테스팅 (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%** 를 달성할 수 있다.

* * *
