소프트웨어 개발의 마지막 관문, 바로 ‘테스트’입니다. 아무리 훌륭한 기능을 가진 소프트웨어라도 예상치 못한 오류로 가득하다면 사용자에게 외면받기 마련이죠. 수많은 테스트 방법론 중에서도, 내부 구조를 몰라도 입력과 출력만으로 시스템의 결함을 찾아내는 ‘블랙박스 테스트(Black-box Test)’는 가장 기본적이면서도 강력한 접근법입니다. 마치 우리가 스마트폰의 복잡한 회로를 몰라도 터치와 앱 실행만으로 기능이 잘 작동하는지 확인하는 것과 같습니다.
블랙박스 테스트는 개발자가 아닌 사용자 관점에서 소프트웨어를 검증하기 때문에 실제 사용 환경에서 발생할 수 있는 오류를 효과적으로 발견할 수 있습니다. 하지만 막상 테스트를 시작하려고 하면, 어디서부터 어떻게 시작해야 할지 막막하게 느껴질 수 있습니다. 본 글에서는 가장 핵심적인 블랙박스 테스트 유형인 동등 분할, 경곗값 분석, 결정 테이블, 상태 전이, 유스케이스 테스트에 대해 심도 있게 파헤쳐 보고, 실제 사례를 통해 어떻게 적용되는지 알아보겠습니다. 이 글을 통해 여러분은 소프트웨어의 품질을 한 단계 끌어올릴 수 있는 강력한 무기를 얻게 될 것입니다.
동등 분할 테스트 (Equivalence Partitioning)
핵심 개념: 입력 데이터를 그룹화하여 효율성 극대화하기
소프트웨어 테스트의 가장 큰 딜레마는 ‘모든 경우의 수를 테스트할 수 없다’는 점입니다. 예를 들어, 1부터 100까지의 숫자를 입력받는 시스템을 테스트한다고 가정해 봅시다. 1, 2, 3, …, 100까지 모든 숫자를 일일이 입력해보는 것은 비효율적입니다. 동등 분할 테스트는 이러한 비효율을 해결하기 위해 등장했습니다. 입력 데이터의 전체 집합을 비슷한 결과를 도출할 것으로 예상되는 부분집합, 즉 ‘동등 클래스(Equivalence Class)’로 나눈 뒤, 각 클래스에서 대표값 하나씩만 선택하여 테스트하는 기법입니다.
동등 분할의 핵심 아이디어는 ‘같은 동등 클래스에 속한 데이터는 시스템이 동일한 방식으로 처리할 것’이라는 가정에 기반합니다. 만약 1부터 100 사이의 유효한 숫자를 입력하는 테스트에서 ‘5’를 입력했을 때 시스템이 정상적으로 동작했다면, ’10’이나 ’99’를 입력해도 동일하게 정상 동작할 것이라고 예측하는 것입니다. 이를 통해 수많은 테스트 케이스를 몇 개의 대표적인 케이스로 압축하여 테스트의 효율성을 획기적으로 높일 수 있습니다.
동등 클래스는 크게 두 가지로 나뉩니다. 첫째는 ‘유효 동등 클래스(Valid Equivalence Class)’로, 시스템 명세서에 정의된 정상적인 입력값들의 집합입니다. 위의 예시에서는 1부터 100까지의 숫자가 여기에 해당합니다. 둘째는 ‘무효 동등 클래스(Invalid Equivalence Class)’로, 시스템이 처리해서는 안 되는 비정상적인 입력값들의 집합입니다. 1보다 작은 숫자(예: 0, -10), 100보다 큰 숫자(예: 101, 200), 그리고 숫자가 아닌 값(예: ‘abc’, ‘가나다’) 등이 무효 동등 클래스에 속합니다. 중요한 점은 각 무효 동등 클래스마다 별도의 테스트 케이스를 작성해야 한다는 것입니다. 왜냐하면 시스템이 각기 다른 종류의 오류를 어떻게 처리하는지 개별적으로 확인해야 하기 때문입니다.
적용 사례: 쇼핑몰 회원가입 나이 입력 필드 테스트
온라인 쇼핑몰의 회원가입 페이지에는 보통 만 14세 이상만 가입할 수 있다는 조건이 있습니다. 이 나이 입력 필드를 동등 분할 기법으로 테스트하는 과정을 살펴보겠습니다.
먼저 입력값의 조건을 분석하여 동등 클래스를 도출합니다.
- 유효 동등 클래스: 14세 이상 (예: 14, 25, 99)
- 무효 동등 클래스 1: 14세 미만 (예: 0, 13)
- 무효 동등 클래스 2: 숫자가 아닌 값 (예: ‘스무살’, ‘abc’)
- 무효 동등 클래스 3: 음수 (예: -1, -100)
- 무효 동등 클래스 4: 입력값이 없는 경우 (공백)
이렇게 도출된 동등 클래스에서 각각 대표값을 선정하여 테스트 케이스를 작성합니다.
| 테스트 케이스 ID | 입력값 | 예상 결과 |
| TC_AGE_001 | 25 | 회원가입 계속 진행 |
| TC_AGE_002 | 13 | ‘만 14세 이상만 가입 가능합니다.’ 경고 메시지 표시 |
| TC_AGE_003 | ‘abc’ | ‘숫자만 입력 가능합니다.’ 경고 메시지 표시 |
| TC_AGE_004 | -10 | ‘유효한 나이를 입력해주세요.’ 경고 메시지 표시 |
| TC_AGE_005 | (공백) | ‘나이를 입력해주세요.’ 경고 메시지 표시 |
이처럼 동등 분할 테스트를 활용하면, 수많은 나이 값을 모두 테스트하지 않고도 단 5개의 테스트 케이스만으로 입력 필드의 유효성 검증 로직을 효과적으로 테스트할 수 있습니다. 이는 테스트 시간과 비용을 크게 절감시켜 줍니다.
경곗값 분석 (Boundary Value Analysis)
핵심 개념: 오류는 언제나 경계에서 발생한다
소프트웨어 개발 경험에 따르면, 수많은 오류는 동등 클래스의 ‘경계’에서 집중적으로 발생합니다. 예를 들어, ’10 이상 20 이하’라는 조건이 있다면, 프로그래머가 코드를 작성할 때 ‘x > 10’이라고 써야 할 것을 ‘x >= 10’으로 잘못 쓰거나, ‘x < 20’으로 코딩하는 실수를 저지르기 쉽습니다. 경곗값 분석은 바로 이러한 점에 착안하여 동등 클래스의 경계가 되는 값과 그 바로 인접한 값들을 집중적으로 테스트하는 기법입니다.
경곗값 분석은 동등 분할 테스트를 보완하고 확장하는 개념으로, 종종 함께 사용됩니다. 동등 분할이 각 클래스의 ‘대표값’을 테스트한다면, 경곗값 분석은 각 클래스의 ‘가장자리’를 테스트하여 잠재적인 오류를 더욱 정밀하게 찾아냅니다. 테스트할 경곗값은 보통 경계 자체, 경계 바로 안쪽 값, 경계 바로 바깥쪽 값으로 구성됩니다.
예를 들어, 1부터 100까지의 숫자를 입력받는 시스템의 경우, 유효 동등 클래스는 [1, 100]입니다. 이때 경곗값 분석을 위한 테스트 값은 다음과 같이 선정할 수 있습니다.
- 최소 경계: 0 (무효), 1 (유효), 2 (유효)
- 최대 경계: 99 (유효), 100 (유효), 101 (무효)
이 값들을 집중적으로 테스트함으로써, ‘미만(<)’, ‘이하(<=)’, ‘초과(>)’, ‘이상(>=)’과 같은 경계 조건 연산자의 오류를 효과적으로 발견할 수 있습니다.
적용 사례: 항공사 마일리지 할인 정책 테스트
어떤 항공사가 마일리지 보유량에 따라 할인율을 차등 적용하는 정책을 새로 도입했다고 가정해 보겠습니다. 정책은 다음과 같습니다.
- 10,000 마일 미만: 할인 없음
- 10,000 마일 이상 ~ 50,000 마일 미만: 5% 할인
- 50,000 마일 이상: 10% 할인
이 정책을 경곗값 분석 기법으로 테스트해 보겠습니다. 먼저 할인율이 변하는 경계 지점인 10,000과 50,000을 중심으로 테스트 값을 선정합니다.
| 테스트 케이스 ID | 입력 마일리지 | 예상 할인율 | 테스트 대상 |
| TC_MILEAGE_001 | 9,999 | 0% | 10,000 경계 바로 아래 |
| TC_MILEAGE_002 | 10,000 | 5% | 10,000 경계 |
| TC_MILEAGE_003 | 10,001 | 5% | 10,000 경계 바로 위 |
| TC_MILEAGE_004 | 49,999 | 5% | 50,000 경계 바로 아래 |
| TC_MILEAGE_005 | 50,000 | 10% | 50,000 경계 |
| TC_MILEAGE_006 | 50,001 | 10% | 50,000 경계 바로 위 |
만약 개발자가 ‘10,000 마일 이상’ 조건을 코드로 구현할 때 ‘mileage > 10000’ 이라고 잘못 작성했다면, TC_MILEAGE_002 케이스에서 예상 결과(5%)와 달리 실제 결과(0%)가 나와 오류를 발견할 수 있습니다. 이처럼 경곗값 분석은 동등 분할만으로는 놓치기 쉬운 논리적인 오류를 정밀하게 찾아내는 데 매우 효과적입니다. 최근에는 금융 시스템의 이자율 계산, 온라인 게임의 레벨업 경험치 구간 등 복잡한 조건이 포함된 시스템에서 경곗값 분석의 중요성이 더욱 부각되고 있습니다.
결정 테이블 테스트 (Decision Table Testing)
핵심 개념: 복잡한 비즈니스 규칙을 표로 명쾌하게 정리하기
소프트웨어의 기능 중에는 여러 가지 조건의 조합에 따라 다른 결과가 나오는 복잡한 비즈니스 로직이 포함된 경우가 많습니다. 예를 들어, 쇼핑몰의 배송비 정책은 ‘회원 등급’, ‘주문 금액’, ‘배송 지역’이라는 여러 조건의 조합에 따라 결정됩니다. 이러한 복잡한 규칙을 일반적인 문장으로 기술하면 모호하거나 누락되는 부분이 발생하기 쉽습니다. 결정 테이블 테스트는 이러한 복잡한 비즈니스 규칙과 그에 따른 행위를 체계적인 표 형식으로 정리하여 테스트 케이스를 설계하는 기법입니다.
결정 테이블은 크게 네 부분으로 구성됩니다.
- 조건 스텁 (Condition Stub): 고려해야 할 모든 조건들을 나열하는 부분입니다. (예: 회원 등급은 VIP인가?)
- 액션 스텁 (Action Stub): 조건에 따라 수행될 수 있는 모든 행위들을 나열하는 부분입니다. (예: 배송비를 2,500원으로 부과한다.)
- 조건 엔트리 (Condition Entry): 각 조건들이 가질 수 있는 값(True/False, Yes/No 등)들을 조합하여 규칙(Rule)을 만드는 부분입니다.
- 액션 엔트리 (Action Entry): 각 규칙에 따라 어떤 행위가 수행되어야 하는지를 표시하는 부분입니다. (X 또는 체크 표시 등)
결정 테이블을 사용하면 복잡하게 얽혀있는 논리적 관계를 시각적으로 명확하게 파악할 수 있으며, 모든 가능한 조건의 조합을 빠짐없이 고려할 수 있어 테스트의 완전성을 높일 수 있습니다. 또한, 불필요하거나 모순되는 규칙을 사전에 발견하여 시스템 설계의 결함을 개선하는 데도 도움이 됩니다.
적용 사례: 은행의 대출 심사 시스템 테스트
한 은행의 신용대출 심사 시스템은 ‘신용 점수’와 ‘연 소득’이라는 두 가지 주요 조건에 따라 ‘대출 승인’, ‘대출 거절’, ‘보증인 요구’라는 세 가지 결과를 결정한다고 가정해 봅시다. 규칙은 다음과 같습니다.
- 규칙 1: 신용 점수가 700점 이상이고, 연 소득이 5,000만원 이상이면 ‘대출 승인’.
- 규칙 2: 신용 점수가 700점 이상이지만, 연 소득이 5,000만원 미만이면 ‘보증인 요구’.
- 규칙 3: 신용 점수가 700점 미만이면 연 소득과 관계없이 ‘대출 거절’.
이 규칙을 결정 테이블로 표현하면 다음과 같습니다.
| 규칙 1 | 규칙 2 | 규칙 3 | 규칙 4 | |
| 조건 | ||||
| 신용 점수 >= 700점 | T | T | F | F |
| 연 소득 >= 5,000만원 | T | F | T | F |
| 액션 | ||||
| 대출 승인 | X | |||
| 보증인 요구 | X | |||
| 대출 거절 | X | X |
이 표를 통해 우리는 각 규칙을 만족하는 테스트 케이스를 명확하게 도출할 수 있습니다. 예를 들어, 규칙 1을 테스트하기 위해 ‘신용 점수 800점, 연 소득 6,000만원’이라는 데이터를 입력하고, 시스템이 ‘대출 승인’ 결과를 내는지 확인합니다. 규칙 3과 4는 모두 ‘대출 거절’로 귀결되므로 하나로 통합하여 테스트 효율을 높일 수도 있습니다.
최근 핀테크(FinTech) 산업이 발전하면서 이처럼 복잡한 금융 상품의 조건을 검증하거나, 보험사의 보험료 산출 로직을 테스트하는 데 결정 테이블 기법이 매우 유용하게 활용되고 있습니다. 이는 시스템의 정확성과 신뢰성을 보장하는 데 결정적인 역할을 합니다.
상태 전이 테스트 (State Transition Testing)
핵심 개념: 시간과 이벤트에 따라 변화하는 시스템의 상태 추적하기
우리가 사용하는 많은 소프트웨어는 사용자의 입력이나 특정 이벤트에 따라 상태(State)가 계속해서 변화합니다. 예를 들어, ATM 기기는 ‘대기’ 상태에서 카드를 삽입하면 ‘카드 인식’ 상태로, 비밀번호를 정확히 입력하면 ‘계좌 선택’ 상태로 변화합니다. 이처럼 시스템이 가질 수 있는 유한한 상태와 상태들 사이의 변화(전이, Transition)를 다이어그램으로 시각화하고, 이를 기반으로 테스트 케이스를 설계하는 기법이 바로 상태 전이 테스트입니다.
이 테스트 기법은 시스템의 특정 상태에서 특정 이벤트가 발생했을 때, 예상된 다음 상태로 올바르게 전이되는지를 확인하는 데 초점을 맞춥니다. 또한, 특정 상태에서 허용되지 않는 이벤트가 발생했을 때 시스템이 어떻게 반응하는지(예: 오류 메시지 출력, 현재 상태 유지)도 중요한 테스트 대상입니다. 상태 전이 다이어그램을 사용하면 시스템의 동적인 흐름을 한눈에 파악할 수 있어, 복잡한 시나리오에서 발생할 수 있는 논리적 결함을 효과적으로 찾아낼 수 있습니다.
상태 전이 테스트는 특히 메뉴 기반의 애플리케이션, 임베디드 시스템, 프로토콜 테스트 등 상태의 변화가 중요한 시스템을 테스트하는 데 매우 유용합니다. 테스트 커버리지 기준으로는 시스템의 모든 상태를 적어도 한 번씩 방문하는 ‘상태 커버리지’, 모든 상태 전이를 한 번씩 테스트하는 ‘전이 커버리지’ 등이 있습니다.
적용 사례: 온라인 쇼핑몰의 주문 프로세스 테스트
온라인 쇼핑몰에서 고객이 상품을 주문하는 과정은 여러 상태를 거치게 됩니다. 이 과정을 상태 전이 다이어그램으로 표현하고 테스트하는 사례를 살펴보겠습니다.
주요 상태: 장바구니, 주문/결제, 주문 완료, 주문 취소
주요 이벤트: 상품 담기, 주문하기, 결제 성공, 결제 실패, 취소 요청
위 다이어그램을 기반으로 다음과 같은 테스트 케이스를 설계할 수 있습니다.
- TC_STATE_001 (정상 흐름):
- 장바구니 상태에서 ‘주문하기’ 버튼 클릭 → ‘주문/결제’ 상태로 전이되는지 확인.
- 주문/결제 상태에서 결제 정보를 입력하고 ‘결제’ 버튼 클릭 → 결제 성공 시 ‘주문 완료’ 상태로 전이되는지 확인.
- TC_STATE_002 (예외 흐름):
- 주문/결제 상태에서 결제 실패 (예: 한도 초과) → 다시 ‘주문/결제’ 상태를 유지하며 오류 메시지를 표시하는지 확인.
- TC_STATE_003 (비정상 전이 테스트):
- 주문 완료 상태에서 ‘상품 담기’ 이벤트 발생 → 아무런 상태 변화가 없는지 확인.
- TC_STATE_004 (취소 흐름):
- 주문 완료 상태에서 ‘취소 요청’ 버튼 클릭 → ‘주문 취소’ 상태로 전이되는지 확인.
최근 구독 경제 모델이 확산되면서 ‘구독 활성’, ‘구독 일시정지’, ‘구독 해지’ 등 고객의 구독 상태를 관리하는 시스템이 많아졌습니다. 이러한 시스템의 안정성을 검증하는 데 상태 전이 테스트는 필수적인 기법으로 자리 잡고 있습니다.
유스케이스 테스트 (Use Case Testing)
핵심 개념: 사용자 입장에서 시스템의 사용 시나리오를 검증하기
지금까지 살펴본 테스트 기법들이 특정 기능이나 로직의 개별적인 측면을 테스트하는 데 중점을 두었다면, 유스케이스 테스트는 실제 사용자가 시스템을 사용하는 시나리오, 즉 ‘유스케이스(Use Case)’를 기반으로 테스트를 설계하는 기법입니다. 유스케이스는 사용자와 시스템 간의 상호작용을 통해 사용자가 특정 목표를 달성하는 과정을 이야기 형식으로 기술한 것입니다. 예를 들어, ‘고객이 온라인 서점에서 책을 검색하고 구매한다’는 하나의 유스케이스가 될 수 있습니다.
유스케이스 테스트의 가장 큰 장점은 개발 초기 단계부터 시스템의 요구사항을 명확히 하고, 이를 기반으로 테스트를 설계함으로써 최종 사용자의 기대를 충족시키는 시스템을 만들 수 있다는 점입니다. 이 테스트는 시스템의 개별 기능들이 통합되었을 때 전체적인 비즈니스 흐름(Business Flow)이 올바르게 동작하는지를 검증하는 데 매우 효과적입니다.
유스케이스는 보통 다음과 같은 요소로 구성됩니다.
- 유스케이스명, 액터(Actor, 사용 또는 시스템과 상호작용하는 주체)
- 사전 조건(Pre-condition): 유스케이스가 시작되기 위해 만족해야 할 조건
- 사후 조건(Post-condition): 유스케이스가 성공적으로 완료된 후의 시스템 상태
- 정상 흐름(Main Success Scenario): 사용자가 목표를 달성하는 가장 일반적인 경로
- 대안 흐름(Alternative Flow): 정상 흐름에서 벗어나는 예외적인 경로
- 예외 흐름(Exception Flow): 오류가 발생했을 때의 처리 경로
테스트 케이스는 이러한 정상 흐름과 대안/예외 흐름을 모두 커버하도록 설계되어야 합니다.
적용 사례: 은행 ATM 현금 인출 시나리오 테스트
은행 ATM에서 고객이 현금을 인출하는 유스케이스를 기반으로 테스트를 설계해 보겠습니다.
- 유스케이스명: 현금 인출
- 액터: 은행 고객
- 사전 조건: ATM이 정상 작동 중이고, 고객은 유효한 카드를 소지하고 있다.
- 정상 흐름:
- 고객이 카드를 삽입한다.
- ATM이 비밀번호 입력을 요청한다.
- 고객이 올바른 비밀번호를 입력한다.
- ATM이 거래 종류(입금, 출금, 조회)를 표시한다.
- 고객이 ‘출금’을 선택한다.
- ATM이 인출 금액 입력을 요청한다.
- 고객이 계좌 잔액 내의 금액을 입력한다.
- ATM이 현금과 명세표를 배출한다.
- 고객이 현금, 명세표, 카드를 수령한다.
- 대안 흐름:
- 7a. 고객이 1회 인출 한도를 초과하는 금액을 입력한다. → ATM이 한도 초과 메시지를 표시하고 다시 금액 입력을 요청한다.
- 예외 흐름:
- 3a. 고객이 비밀번호를 3회 연속 틀리게 입력한다. → ATM이 카드를 회수하고 거래를 중단한다.
- 7b. 고객이 계좌 잔액을 초과하는 금액을 입력한다. → ATM이 잔액 부족 메시지를 표시하고 거래를 중단한다.
이 유스케이스를 기반으로 각 흐름(정상, 대안, 예외)을 검증하는 테스트 시나리오를 작성하여, 실제 사용자의 입장에서 발생할 수 있는 다양한 상황을 종합적으로 테스트할 수 있습니다. 최근 애자일(Agile) 개발 방법론에서는 사용자 스토리(User Story)를 기반으로 개발과 테스트를 진행하는데, 이는 유스케이스 테스트의 개념과 매우 유사하여 실제 비즈니스 가치를 제공하는 기능을 중심으로 품질을 확보하는 데 큰 도움이 됩니다.
마무리: 블랙박스 테스트의 중요성과 적용 시 주의점
지금까지 우리는 소프트웨어의 품질을 보증하는 핵심적인 블랙박스 테스트 기법들을 살펴보았습니다. 동등 분할과 경곗값 분석은 테스트 케이스의 수를 획기적으로 줄여 효율성을 높여주고, 결정 테이블은 복잡한 비즈니스 규칙을 명료하게 만들어주며, 상태 전이 테스트는 시스템의 동적인 흐름을, 유스케이스 테스트는 실제 사용자 시나리오를 검증하는 데 각각 특화되어 있습니다. 이 기법들은 서로 배타적인 것이 아니라, 테스트 대상 시스템의 특징에 맞게 상호 보완적으로 사용될 때 가장 큰 효과를 발휘합니다.
블랙박스 테스트 기법을 성공적으로 적용하기 위해서는 몇 가지 주의점이 필요합니다. 첫째, 테스트의 기반이 되는 요구사항 명세서가 명확하고 완전해야 합니다. 명세서 자체가 모호하다면 어떤 테스트 기법을 사용하더라도 효과적인 테스트 케이스를 도출하기 어렵습니다. 둘째, 한 가지 기법에만 의존해서는 안 됩니다. 시스템의 복잡도와 특성을 고려하여 여러 기법을 조합하는 것이 테스트 커버리지를 높이는 지름길입니다. 마지막으로, 테스트는 단순히 결함을 찾는 활동을 넘어, 소프트웨어의 품질을 전체적으로 향상시키는 과정이라는 인식을 갖는 것이 중요합니다.
결국 블랙박스 테스트는 사용자에게 더 나은 가치를 제공하기 위한 필수적인 과정입니다. 오늘 소개된 기법들을 잘 이해하고 현업에 적용한다면, 여러분은 사용자의 신뢰를 얻는 견고하고 안정적인 소프트웨어를 만드는 데 한 걸음 더 다가갈 수 있을 것입니다.
