이 글은 STEN에서 공유한 '소프트웨어 테스트 실무 가이드 Part 1' 도서를 읽고 SW 테스트의 개념들을 정리한 글로, 책에서 나온 내용과 개인적으로 웹 검색 등을 통해 학습한 내용을 함께 작성했다.
1. 테스트 설계 기법
명세 기반 테스트 설계 (Specification-based Testing)
기능/요구사항 명세서 또는 기획서 등을 기준으로 테스트 케이스를 설계하는 방법. 시스템의 기능과 동작을 테스트하는데 중점을 두며, 블랙박스 테스트 기법이 주로 사용된다. 이 설계 기법의 테스트 케이스는 외부 동작과 기대 결과에 기반해 작성된다.
명세 기반 테스트 예시
아래와 같은 요구사항 명세서(기획서)가 존재할 때, 명세 기반 테스트 기법으로 여러가지 방법을 사용할 수 있다.
# 요구사항 예시 (ex. 대학교 학점 계산 시스템)
- 시험 점수: 0~70 사이 정수
- 과제 점수: 0~20 사이 정수
- 출석 점수: 0~10 사이 정수
- A학점은 80점 이상, C학점은 49점 이하, 그 외에는 B학점
동등 분할 테스트
테스트 항목의 입/출력이 여러 개의 독립된 영역으로 구분되는 경우에 적용된다. 동일 영역 내에서는 어떠한 값을 선택해도 결과가 항상 같다는 원리를 이용하며, 모든 영역에서 최소 하나 이상의 값을 선택해 테스트한다. TC를 작성한다면, 아래와 같은 예시가 나올 수 있다. (A학점은 80점 이상, C학점은 50점 이하일 때)
TC | 입력값 또는 조건 | 기대 결과 | |||
시험 점수 | 과제 점수 | 출석 점수 | 총점 | ||
1 | -10 | -20 | -30 | -60 | 경고 메시지 출력 |
2 | 20 | 20 | 5 | 45 | C학점 |
3 | 25 | 20 | 10 | 55 | B학점 |
4 | 65 | 15 | 10 | 90 | A학점 |
5 | 80 | 30 | 15 | 125 | 경고 메시지 출력 |
입력 유효 범위를 기준으로 더 적게 입력했을 때/올바르게 입력했을 때/더 많이 입력했을 때의 케이스를 동등하게 분할하여 테스트하도록 했으며, 각 출력 결과(A/B/C학점) 또한 모두 동등 분할해 테스트 케이스를 작성했다.
경계 값 분석 테스트
특정 영역의 상한 또는 하한 경계값을 테스트 데이터로 선택하는 테스트 기법으로, 유효 범위에서 가장 작은 수(하한 경계값)와 가장 큰 수(상한 경계값)를 입력해 테스트 하는 기법이다. 경계값을 사용하는 이유는 유효 범위의 '시작'과 '끝'을 가리키는 수이기 때문에, 상대적으로 결함 발생 가능성이 높기 때문이다. 이 방법을 사용해 TC를 작성한다면 아래와 같은 예시가 나오게 된다.
먼저, 입력 값을 기준으로 경계 값 분석 테스트 케이스를 작성한 예시다. 2Bytes 정수만을 입력받는다고 가정하면 입력 가능한 범위는 -32,768 ~ 32,767이고, 그 중 유효한 입력 범위는 위 요구사항 명세서에서 제시한 대로다.
TC | 입력 값(2Bytes 정수 입력 기준) | 기대 결과 | |||
시험 점수 | 과제 점수 | 출석 점수 | 총점 | ||
1 | -32,768 | -32,768 | -32,768 | -98,304 | 경고 메시지 |
2 | -1 | -1 | -1 | -3 | 경고 메시지 |
3 | 0 | 0 | 0 | 0 | C학점 |
4 | 70 | 20 | 10 | 100 | A학점 |
5 | 71 | 21 | 11 | 103 | 경고 메시지 |
6 | 32,767 | 32,767 | 32,767 | 98,301 | 경고 메시지 |
하지만 입력값의 범위만을 고려한 위의 경우에는 'B학점'에 대한 출력 결과에 대한 TC가 없다. 따라서, 출력 결과(총점 및 기대 결과)에 대한 경계값 분석 테스트도 필요하다.
TC | 입력 값 | 기대 결과 | 경계값 구분 | |||
시험 점수 | 과제 점수 | 출석 점수 | 총점 | |||
1 | 60 | 15 | 5 | 80 | A학점 | A학점 하한 경계값 |
2 | 70 | 20 | 10 | 100 | A학점 | A학점 상한 경계값 |
3 | 35 | 8 | 7 | 50 | B학점 | B학점 하한 경계값 |
4 | 59 | 12 | 8 | 79 | B학점 | B학점 상한 경계값 |
5 | 0 | 0 | 0 | 0 | C학점 | C학점 하한 경계값 |
6 | 43 | 4 | 2 | 49 | C학점 | C학점 상한 경계값 |
7 | -30,000 | -2,000 | -768 | -32,768 | 경고 메시지 | 경고 하한 경계값(-) |
8 | 10 | -9 | -2 | -1 | 경고 메시지 | 경고 상한 경계값(-) |
9 | 25 | 70 | 6 | 101 | 경고 메시지 | 경고 하한 경계값(+) |
10 | 767 | 2,000 | 30,000 | 32,767 | 경고 메시지 | 경고 상한 경계값(+) |
위처럼 출력 결과를 고려한 테스트 케이스 작성으로 B학점에 대한 기대 결과값도 테스트할 수 있게 되었다. 경계값 분석은 일반적으로 동등 분할 기법과 함께 사용하며, 연속적인 값이 입/출력으로 주어질 때 사용할 수 있다.
조합 테스트(페어와이즈 기법)
조합 테스트는 동등 분할 조건의 모든 조합에 대해서 테스트를 진행하는 것을 의미한다. 하지만 현실적으로 모든 조합을 테스트하는 '전수 테스트'는 시간과 비용 등의 이슈로 불가능한 경우가 많다. 책에서는 이 문제를 해결할 대안으로 '페어와이즈 기법'을 소개한다.
페어와이즈 기법은 각 변수의 가능한 값들이 최소한 한 번 이상 서로 조합되는 방식으로 TC를 도출하는 기법이다. 모든 조합을 테스트하지 않고도 효과적으로 커버리지를 확보할 수 있다. 예를 들어, OTT 서비스에서 아래와 같은 테스트 조건이 있다고 가정해보자.
# OTT 서비스 예시 - 각 변수 조건
- 네트워크 환경: Wi-Fi, 5G, LTE
- 기기 유형: 스마트TV, 모바일, 태블릿
- 해상도: 720p, 1080p, 4K
- 자막: 한국어, 영어, 없음
위에서 주어진 조건에 따라 모든 조합을 테스트 하려면, 3(네트워크)*3(기기 유형)*3(해상도)*3(자막) = 81개의 TC가 필요하다. 하지만 페어와이즈 기법을 통해 모든 변수 조합이 최소 한 번 이상 포함되는 TC를 9~10개 정도로 생성해 테스트할 수 있다.
위처럼 페어와이즈 기법을 사용하면 각 변수 값이 최소한 한 번 이상 TC에 포함시킬 수 있다. 여러 조합을 바꿔가며 테스트하는 것이기 때문에, Selenium 또는 Playwright와 같은 자동화 프레임워크와 결합해서 더 효율적으로 사용할 수도 있다.
페어와이즈 조합은 자동 생성 도구를 통해 손 쉽게 생성할 수 있는데, 대표적으로 아래와 같은 종류들이 있다.
- AllPairs (무료 / CLI 기반)
- PICT (MS에서 제공)
- Hexawise (GUI 지원)
- ChatGPT와 같은 AI 도구 이용
전이 테스트
전이 테스트는 SW 시스템이 특정 상태에서 다른 상태로 전이(transition)할 때의 동작을 검증하는 테스트 기법이다. 상태(State)와 상태 간 전이에 초점을 맞추며, 주로 상태 머신(State Machine) 모델을 기반으로 테스트를 설계한다.
최근 웹/앱 서비스의 복잡성이 늘어남으로써, 전이 테스트의 중요성이 높아지고 있다. 단순한 입/출력 구조가 아닌 여러 상태(ex. 로그인, 결제 진행 등)를 가지는 경우가 많기 때문에, 각 상태와 상태 변화에 따라 작동하는지 검증할 필요가 있다.
로그인 동작을 검증하는 테스트를 진행한다고 했을 때, 전이 테스트는 아래와 같은 예시로 TC를 작성할 수 있다. 먼저, 상태가 전이되는 프로세스를 담은 다이어 그램을 그려본다면 아래와 같다.
[로그아웃] → (로그인 시도) → [인증 중] → (성공) → [로그인 완료]
↳ (실패) → [로그아웃]
TC | 현재 상태 | 입력 (이벤트) | 기대 결과 (전이 후 상태) |
1 | 로그아웃(미로그인) | 로그인 시도 | 인증 중 |
2 | 인증 중 | 올바른 정보 입력 | 로그인 완료 |
3 | 인증 중 | 잘못된 정보 입력 | 로그아웃 |
4 | 로그인 완료 | 로그아웃 버튼 클릭 | 로그아웃 |
좀 더 복잡한 과정을 다뤄보자. 아래와 같이 ATM에서 현금을 인출하는 과정은 더 많은 상태를 거친다.
[대기 상태] → (카드 삽입) → [PIN 입력] → (올바른 PIN 입력) → [메뉴 선택]
↳ (잘못된 PIN 입력) → [대기 상태]
[메뉴 선택] → (현금 인출 선택) → [출금 처리] → (성공) → [대기 상태]
↳ (잔액 부족) → [메뉴 선택]
TC | 현재 상태 | 입력(이벤트) | 기대 결과 (전이 후 상태) |
1 | 대기 상태 | 카드 삽입 | PIN 입력 |
2 | PIN 입력 | 올바른 PIN 입력 | 메뉴 선택 |
3 | PIN 입력 | 잘못된 PIN 입력 | 대기 상태 (카드 압류) |
4 | 메뉴 선택 | 현금 인출 선택 | 출금 처리 |
5 | 출금 처리 | 잔액 부족 | 메뉴 선택 |
6 | 출금 처리 | 성공 | 대기 상태 |
전이 테스트 또한 조합 테스트와 마찬가지로 시나리오에 따라 다양한 조합이 있지만, 시간과 비용 문제로 모든 조합을 시행하긴 어렵다. 따라서 페어와이즈 등의 기법을 활용해 주요 상태 조합을 먼저 테스트한 뒤, 예외적인 상태 전이에 대한 검증(ex. 로그아웃 상태에서 결제 시도 등)을 진행할 필요가 있다.
사용사례 테스트
사용사례 테스트는 사용자의 관점에서 시스템을 테스트하는 기법으로, SW가 실제 사용 시나리오에서 기대하는 동작을 수행하는지를 중점적으로 테스트한다. 주로 E2E(End-to-End) 테스트에 활용하는 기법이다.
사용자가 실제로 서비스를 이용하는 시나리오를 기반으로 TC를 작성하고, 해당 사용자가 목표를 달성하는 것을 중심으로 테스트를 수행한다. E2E 테스트에 활용되는 기법인 만큼 기능 간 연계를 검증하고, 전체적인 흐름과 예외 사항을 포함하는 테스트다.
사용사례 테스트는 아래와 같은 요소를 포함해 TC를 작성한다.
- 액터(Actor): 시스템을 사용하는 주체(사용자, 유저, 외부 시스템, 관리자 등)
- 사용사례(Use Case): 특정 기능을 수행하는 과정(ex. 로그인, 상품 구매, 동영상 시청 등)
- 이벤트 흐름(Flow): 사용자가 시스템과 상호작용하는 단계
- 주 흐름(main flow): 정상적인 시나리오
- 대체 히름(alternate flow): 예외 처리 및 분기 발생 시나리오(ex. 비밀번호 오류)
- 사전 조건(Precondition): 테스트를 수행하기 전 시스템이 충족해야하는 조건(ex. 회원가입이 완료된 상태)
- 후 조건(Postcondition): 테스트 완료 후 시스템이 만족해야 하는 조건 (ex. 로그인 성공 시 홈 화면으로 이동)
이제 쇼핑몰에서 상품을 구매하는 시스템을 예시로 TC를 작성해보자.
# 상품 구매 시스템
[사용자] → (상품 선택) → (장바구니 추가) → (결제 진행) → (결제 완료)
↳ (결제 오류) → (재시도)
TC | 액터 | 이벤트 흐름 | 기대 결과 |
1 | User1 | 상품 선택 → 장바구니 추가 → 결제 | 결제 완료 & 주문 확인 페이지 이동 |
2 | User2 | 상품 선택 → 장바구니 추가 → 카드 정보 오류 입력 | 결제 실패 & 오류 메시지 표시 |
3 | User3 | 상품 선택 → 품절된 상품 선택 | 구매 불가 & 품절 안내 메시지 |
4 | User4 | 상품 선택 → 결제 진행 중 인터넷 끊김 | 결제 실패 & 네트워크 오류 메시지 |
2. 구조 기반 테스트 설계 기법 (Structure-based Testing)
SW 내부의 코드 구조, 설계, 아키텍처 등을 기준으로 TC를 설계하는 방법. 시스템의 내부 구조를 테스트하는 데 중점을 두며, 화이트박스 테스트 기법이 주로 사용된다. TC는 코드의 실행 경로, 조건, 루프 등을 고려해 작성된다. 커버리지 라는 기준을 주로 사용한다.
구조 기반 테스트 예시
문장 커버리지
문장 커버리지는 코드 상의 모든 문장이 실행되는지 확인하기 위해 TC를 작성한다. 예를 들어, 아래와 같은 간단한 Python 함수가 있다고 가정하자.
def add_num(a, b):
sum = a + b
if sum > 100:
sum = 100
return sum
위 함수는 변수 a와 b를 인자로 받으며, if 조건문이 존재한다. 따라서, if문을 실행하는 입력값과 실행하지 않는 입력값을 인자로 주어 모든 문장이 실행되도록 한다.
TC | 입력 값 | 기대 결과(sum) | |
a | b | ||
1 | 50 | 30 | 80 (if문 실행하지 않음) |
2 | 60 | 50 | 100 (if문 실행) |
조건 커버리지
조건 커버리지는 특정 조건에 따라 결과값이 달라지는 함수(또는 최소 단위)에 대해 각 개별 조건의 참과 거짓이 최소한 한 번씩 실행되는지 확인하는 테스트 기법이다. 아래 함수를 기준으로 TC를 작성해본다고 가정하자.
def check_discount(member, purchase_amount):
if member == "VIP" or purchase_amount > 100: # 조건 A: member == "VIP", 조건 B: purchase_amount > 100
return "Discount Applied"
else:
return "No Discount"
위 함수의 if 조건문에는 2가지의 조건이 있다.
- 조건 A: member == "VIP"
- 조건 B: purchase_amount > 100
각 개별 조건에 대해 참과 거짓이 최소 한 번씩 실행될 수 있도록 TC를 작성해보자.
TC | member | purchase_amount | 조건 A | 조건 B | 기대 결과 |
1 | "VIP" | 50 | True | False | Discount Applied |
2 | "Normal" | 150 | False | True | Discount Applied |
3 | "Normal" | 50 | False | False | No Discount |
위 3가지 케이스를 통해 각 조건이 최소 한 번씩 True또는 False값을 가지고 실행되었다.
조건/분기 커버리지(Condition/Decision Coverage, C/DC)
그런데 위 조건 커버리지를 살펴보면, 조건 A와 B가 모두 True인 상황에 대해서는 테스트를 하지 않고 있다. 입력 값에 대한 True, False 조건만을 살피기 때문에, 전체 분기(Branch)를 모두 커버하지는 못한다. 이런 상황에서는 조건/분기 커버리지를 사용해 논리적으로 강력한 검증을 통해 보완할 수 있다. 이번엔 and가 있는 if 조건문에 대해서 살펴보자.
def is_eligible(age, is_member):
if age >= 18 and is_member: # 조건 A: age >= 18, 조건 B: is_member
return "Eligible"
else:
return "Not Eligible"
위와 마찬가지로 조건이 2가지다.
- 조건 A: age > 18
- 조건 B: is_member
조건/분기 커버리지에서는 각 조건에 대해서 True/False가 최소 한 번씩 실행될 뿐만 아니라, 모든 분기(if, else)에 대해서도 최소 한 번씩 실행되어야 하는 TC 설계 조건을 가진다.
TC | age | is_member | 조건 A | 조건 B | 분기 실행 결과 | 기대 결과 |
1 | 20 | True | True | True | if 실행 | Eligible |
2 | 17 | True | False | True | else 실행 | Not Eligible |
3 | 21 | False | False | False | else 실행 | Not Eligible |
4 | 16 | False | False | False | else 실행 | Not Eligible |
조건/분기 커버리지 기법에서는 위와 같이 (True, True)를 가진 TC도 포함된다는 것을 알 수 있다.
'Minding's Programming > Knowledge' 카테고리의 다른 글
[OmniParserV2] LLM과 함께 사용할 수 있는 화면 인식 GUI 자동화 도구 (설치 및 실행 방법) (1) | 2025.02.25 |
---|---|
[Python 3.13] Python에서 GIL을 비활성화 할 수 있다? (0) | 2025.02.24 |
[QA/Testing] 모바일 앱 테스트 자동화 오픈소스 Appium 사용해보기 (0) | 2025.02.20 |
[프로젝트] Catch Me My Capital - 합리적인 투자 의사결정을 위한 금융 데이터 파이프라인 및 백테스팅 도구 (테스트 도입 편) (0) | 2025.02.18 |
[QA/Testing] Charles를 이용해 테스트해보기 (Throttle test, Breakpoint test) (0) | 2025.02.15 |