변경 조건/결정 커버리지 테스팅 (Modified Condition/Decision Coverage Testing, MC/DC)#
MC/DC는 결정문 내의 각 조건이 독립적으로 결정의 결과에 영향을 미치는지 확인하는 테스트 기법이다.
이는 조건 커버리지와 결정 커버리지를 확장한 개념으로, 복잡한 논리 표현식의 각 입력이 출력에 미치는 영향을 독립적으로 보여준다.
먼저, MC/DC의 기본 개념을 이해하기 쉬운 예제를 통해 살펴보자:
1
2
3
| public boolean validateFlight(boolean autopilotEngaged, boolean altitude, boolean airspeed) {
return autopilotEngaged && (altitude || airspeed);
}
|
이 코드는 비행 조건을 검증하는 간단한 함수이다. 자동조종장치가 켜져 있고, 고도나 속도 중 하나가 적절한 경우에만 비행이 허용된다.
MC/DC에서는 각 조건이 독립적으로 전체 결과에 영향을 미치는 것을 검증해야 한다.
MC/DC를 만족하기 위한 테스트 케이스를 설계해보자:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| @Test
void testFlightValidation() {
// autopilotEngaged의 영향을 테스트 (다른 조건은 고정)
assertTrue(validateFlight(true, true, false)); // autopilot이 true일 때
assertFalse(validateFlight(false, true, false)); // autopilot이 false일 때
// altitude의 영향을 테스트 (autopilot = true로 고정)
assertTrue(validateFlight(true, true, false)); // altitude가 true일 때
assertFalse(validateFlight(true, false, false)); // altitude가 false일 때
// airspeed의 영향을 테스트 (autopilot = true, altitude = false로 고정)
assertTrue(validateFlight(true, false, true)); // airspeed가 true일 때
assertFalse(validateFlight(true, false, false)); // airspeed가 false일 때
}
|
이제 더 복잡한 예제를 통해 MC/DC의 중요성을 자세히 살펴보자:
1
2
3
4
5
6
7
8
9
10
11
| public class MedicalAlertSystem {
public boolean requiresEmergencyResponse(
boolean highHeartRate,
boolean lowBloodPressure,
boolean highTemperature,
boolean lowOxygenLevel
) {
return (highHeartRate && lowBloodPressure) ||
(highTemperature && lowOxygenLevel);
}
}
|
이 의료 경보 시스템에서 MC/DC를 만족하기 위한 테스트 케이스를 설계해보면:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| @Test
void testMedicalEmergencySystem() {
MedicalAlertSystem system = new MedicalAlertSystem();
// 첫 번째 조건부 (highHeartRate && lowBloodPressure) 테스트
// highHeartRate의 독립적 영향
assertTrue(system.requiresEmergencyResponse(true, true, false, false));
assertFalse(system.requiresEmergencyResponse(false, true, false, false));
// lowBloodPressure의 독립적 영향
assertTrue(system.requiresEmergencyResponse(true, true, false, false));
assertFalse(system.requiresEmergencyResponse(true, false, false, false));
// 두 번째 조건부 (highTemperature && lowOxygenLevel) 테스트
// highTemperature의 독립적 영향
assertTrue(system.requiresEmergencyResponse(false, false, true, true));
assertFalse(system.requiresEmergencyResponse(false, false, false, true));
// lowOxygenLevel의 독립적 영향
assertTrue(system.requiresEmergencyResponse(false, false, true, true));
assertFalse(system.requiresEmergencyResponse(false, false, true, false));
}
|
MC/DC의 주요 요구사항#
- 모든 진입점과 출구점이 실행되어야 한다.
- 모든 조건이 가능한 모든 결과를 가져야 한다.
- 각 조건이 다른 조건과 독립적으로 전체 결정의 결과에 영향을 미쳐야 한다.
- 각 결정이 가능한 모든 결과를 가져야 한다.
실제 개발 현장에서 MC/DC를 적용할 때 주의해야 할 점#
단축 평가(Short-circuit evaluation) 고려:
1
2
3
| public boolean checkSafety(boolean primarySystem, boolean backupSystem) {
return primarySystem || (backupSystem && isPowerAvailable());
}
|
이 경우, primarySystem이 true일 때는 나머지 조건이 평가되지 않는다는 점을 고려해야 한다.
중첩된 조건의 처리:
1
2
3
4
5
6
7
8
| public boolean validateProcess(boolean condition1, boolean condition2) {
if (condition1) {
if (condition2) {
return true;
}
}
return false;
}
|
중첩된 조건에서는 각 조건의 독립적 영향을 더 신중하게 검증해야 한다.
주요 특징#
- 각 조건의 독립적 영향 검증: 결정문 내의 모든 조건이 독립적으로 결과에 영향을 미치는지 확인한다.
- 효율적인 테스트 케이스: n개의 조건에 대해 최소 n+1개의 테스트 케이스만으로 100% 커버리지를 달성할 수 있다[1].
- 안전 중요 시스템에 적합: 항공, 자동차, 의료 기기 등 안전이 중요한 산업에서 널리 사용된다.
- 높은 오류 검출 확률: 복잡한 조건문에서 발생할 수 있는 오류를 효과적으로 찾아낼 수 있다.
- 테스트 케이스 수 감소: 다중 조건 커버리지(MCC)에 비해 훨씬 적은 수의 테스트 케이스로 높은 커버리지를 달성할 수 있다.
- 안전 중요 시스템의 신뢰성 향상: 철저한 테스트를 통해 소프트웨어의 신뢰성을 높일 수 있다.
한계점#
- 테스트 케이스 설계의 복잡성: 각 조건의 독립적 영향을 보여주는 테스트 케이스를 설계하는 것이 어려울 수 있다.
- 시간과 비용: 완전한 MC/DC 달성을 위해서는 상당한 시간과 리소스가 필요하다.
- 도구 지원의 필요성: 복잡한 조건에서 MC/DC 분석을 수행하기 위해서는 자동화된 도구의 지원이 필요할 수 있다.
적용 방법#
- 모든 결정문 식별: 프로그램 내의 복잡한 불리언 조건을 포함한 모든 결정문을 식별한다.
- 테스트 케이스 설계: 각 조건이 독립적으로 결과에 영향을 미치도록 테스트 케이스를 설계한다.
- 테스트 실행 및 분석: 설계된 테스트 케이스를 실행하고 결과를 분석하여 각 조건의 독립적 영향을 확인한다.
- 커버리지 측정: MC/DC 기준에 따라 커버리지를 측정하고 필요한 경우 추가 테스트를 수행한다.
MC/DC는 복잡한 의사결정 구조를 철저히 테스트하여 숨겨진 결함을 찾아내는 데 효과적인 테스트 기법이다.
특히 안전이 중요한 시스템에서 소프트웨어의 신뢰성을 높이는 데 큰 도움이 된다.
참고 및 출처#