목차39개 항목
출처와 참고
품질 특성, 검증과 확인, 정적·동적 기법, 테스트 설계 기법, 테스트 프로세스와 위험 기반 테스트, AI 소프트웨어 테스트 절은 고려사이버대학교 「소프트웨어 테스트」(2024-1학기)와 「소프트웨어공학」(2024-1학기) 강의 내용으로 보강했다. McCall 품질 모델, 품질 보증·품질 관리·감사와 테스트의 구분, 시스템 테스트의 종류, 기초 경로 검사는 GitHub 자료 모음 「Subjective-studies_OS-CN-DBMS」의 소프트웨어 공학 튜토리얼을 바탕으로 보강했다.
테스트는 결함을 찾아 품질을 확인하는 활동이다. 시험에서는 "무엇을 기준으로(품질 특성), 언제(테스트 레벨), 어떻게(블랙박스·화이트박스 기법), 무엇과 비교해서(오라클), 무엇으로(하네스·자동화 도구)" 테스트하는지를 반복해서 묻는다. 실무에서는 여기에 "얼마나 테스트하면 끝인가(완료 기준, 위험 기반 테스트)"가 더해진다.
소프트웨어 품질과 ISO/IEC 25010
품질은 명시된 요구와 드러나지 않은 기대를 함께 만족시키는 제품·서비스의 능력이다. 제품 품질은 만드는 과정의 품질에 달려 있어서(프로세스 품질), 품질 확보는 마지막 테스트 한 번이 아니라 개발 전 과정의 활동이 된다.
품질 특성을 나누는 시도는 1977년 McCall 모델에서 시작됐다. 제품을 세 관점에서 본다. 운영(operation: 정확성, 신뢰성, 효율성, 무결성, 사용성), 개정(revision: 유지보수성, 유연성, 시험성), 전이(transition: 이식성, 재사용성, 상호 운용성)다. 이 생각을 다듬어 국제 표준이 된 것이 ISO/IEC 9126이고, 지금은 그 후속인 ISO/IEC 25010(SQuaRE) 의 제품 품질 모델이 무엇을 품질로 볼지 정한다. 시험과 강의에서 주로 쓰는 2011년판은 품질 특성 8개와 부특성으로 나눈다.
| 품질 특성 | 질문 | 부특성 |
|---|---|---|
| 기능 적합성 | 필요한 기능을 정확하게 다 갖췄나 | 기능 완전성, 기능 정확성, 기능 적절성 |
| 성능 효율성 | 자원 대비 빠른가 | 시간 반응성, 자원 활용성, 수용량 |
| 호환성 | 다른 제품과 함께 쓰고 정보를 주고받나 | 공존성, 상호 운용성 |
| 사용성 | 쉽게 배우고 쓰나 | 적합성 인식, 학습성, 운용성, 사용자 오류 보호, UI 미학, 접근성 |
| 신뢰성 | 정해진 조건에서 계속 제대로 도나 | 성숙성, 가용성, 결함 허용성, 복구성 |
| 보안성 | 허가된 사람만 허가된 만큼 쓰나 | 기밀성, 무결성, 부인 방지, 책임 추적성, 인증성 |
| 유지보수성 | 고치기 쉬운가 | 모듈성, 재사용성, 분석성, 수정성, 시험성 |
| 이식성 | 다른 환경으로 옮기기 쉬운가 | 적응성, 설치성, 대체성 |
2023년 개정판은 특성을 9개로 바꿨다. 사용성은 상호작용 능력(interaction capability), 이식성은 유연성(flexibility) 으로 이름과 범위가 넓어졌고, 안전성(safety) 이 새로 들어왔다. 사용성을 실제로 재는 방법은 사용자 리서치의 사용성 평가에, 안전 필수 시스템의 품질 확보는 소프트웨어 안전에, AI 소프트웨어에 더해지는 품질 특성은 아래 「AI 소프트웨어 테스트」 절에 있다.
테스트, 품질 관리, 품질 보증, 감사
네 활동은 모두 품질을 위한 것이지만 보는 대상이 다르다.
| 활동 | 대상 | 묻는 것 |
|---|---|---|
| 테스트 | 제품 | 실행해 보니 결함이 있나 |
| 품질 관리(QC) | 제품 | 이 제품이 기능·비기능 기준을 충족해 고객에게 내보낼 만한가. 테스트와 리뷰가 수단이다 |
| 품질 보증(QA) | 프로세스 | 조직이 정한 표준과 방법대로 개발했나. 결함을 찾기보다 결함이 생기지 않게 과정을 감시한다 |
| 감사(audit) | 프로세스 | 개발에 쓴 절차가 표준·계약에 맞았는지 독립된 감사 팀이 검토한다 |
QC는 결과물을 걸러 내는 사후 활동이고, QA는 과정을 바로잡는 예방 활동이다. 프로세스 성숙도를 평가하는 CMMI는 소프트웨어 프로젝트 관리에 있다.
테스트 원리
- 결함 집중(파레토): 결함의 대부분은 소수의 모듈에 몰려 있다.
- 살충제 패러독스: 같은 테스트 케이스를 반복하면 더 이상 새로운 결함을 찾지 못한다 → 테스트 케이스를 주기적으로 점검·개선해야 한다.
- 오류-부재의 궤변: 결함이 없어도 사용자 요구를 만족하지 못하면 품질이 높다고 할 수 없다.
- 완벽한 테스트는 불가능하고, 테스트는 결함이 있음을 보여 줄 뿐 없음을 증명하지 못한다.
에러, 결함, 고장
| 용어 | 뜻 | 예 (평균 계산 함수) |
|---|---|---|
| 에러(Error) | 사람의 실수 | 항목이 0개인 경우를 생각하지 못했다 |
| 결함(Defect, Fault, Bug) | 실수 때문에 제품 안에 남은 결점 | 개수가 0일 때를 처리하는 코드가 없다 |
| 고장(Failure) | 결함이 있는 부분이 실행되어 겉으로 드러난 현상 | 빈 목록을 넘기자 0으로 나누기 예외가 난다 |
결함이 있어도 그 코드가 실행되지 않으면 고장은 일어나지 않는다. 테스트는 고장을 일으켜 결함을 드러내는 활동이다. 결함은 소프트웨어 → 서브시스템 → 시스템 → 최종 제품으로 전파되며, 끝에서는 위험원(hazard)과 사고로 이어질 수 있다(소프트웨어 안전).
| 구분 | 테스트 | 디버깅 |
|---|---|---|
| 목적 | 아직 모르는 결함을 찾는다 | 이미 아는 결함을 고친다 |
| 담당 | 개발자, 테스트 팀 같은 제3자도 | 개발자 |
| 주요 작업 | 결함 검출 | 결함 위치 파악, 유형 식별, 수정 |
디버깅 요령은 디버깅하는 마음가짐에 있다.
테스트 레벨 (V-모델)
V-모델은 개발 단계와 테스트 단계를 짝지어 보여 준다. 오른쪽 테스트를 왼쪽 개발과 병행해서 계획·설계하므로, 테스트 설계는 코딩이 끝난 뒤가 아니라 해당 개발 단계에서 시작한다. 각 레벨에서 테스트 케이스를 뽑는 근거가 되는 개발 산출물을 테스트 베이시스라 한다.
| 개발 단계 | 대응 테스트 | 내용 | 테스트 베이시스 |
|---|---|---|---|
| 요구사항 분석 | 인수 테스트 | 사용자가 요구사항 충족 여부를 직접 확인 | 고객 요구사항 정의서 |
| 분석·설계 | 시스템 테스트 | 실제와 비슷한 환경에서 전체 시스템 점검 | 요구사항 명세서, 유스케이스 명세 |
| 상세 설계 | 통합 테스트 | 모듈 간 인터페이스·상호작용 오류 검사 | 아키텍처 설계서 |
| 코딩 | 단위 테스트 | 모듈·컴포넌트 단위(모듈 테스트). 주로 화이트박스 | 상세 설계서, 소스 코드 |
인수 테스트의 종류
- 사용자 인수, 운영상 인수, 계약 인수, 규정 인수
- 알파 테스트: 개발자 장소에서, 개발자가 지켜보는 가운데 사용자가 수행 (통제된 환경)
- 베타 테스트: 실제 사용 환경에서 최종 사용자가 수행하고 문제를 보고
회귀 테스트: 수정 후 기존 기능에 새로운 오류가 생기지 않았는지 다시 확인한다.
시스템 테스트는 완성된 제품 전체를 대상으로 목적별로 나눠 한다.
| 종류 | 확인하는 것 |
|---|---|
| 기능 테스트 | 모든 기능이 요구사항대로 동작하나 |
| 성능 테스트 | 응답 시간과 처리량. 예상 부하에서 보는 부하 테스트와 한계를 넘겨 무너지는 지점과 회복을 보는 스트레스 테스트로 나뉜다 |
| 보안 테스트 | 허가되지 않은 접근과 공격을 막나 |
| 이식성·호환성 테스트 | 여러 플랫폼·환경에서 같은 동작을 하나 |
| 복구 테스트 | 장애를 일부러 일으킨 뒤 정해진 시간 안에 복구되나 |
검증과 확인 (V&V)
| 구분 | 검증(Verification) | 확인(Validation) |
|---|---|---|
| 질문 (Boehm) | 제품을 올바르게 만들고 있나? | 올바른 제품을 만들고 있나? |
| 기준 | 명세(스펙)에 맞나 | 사용자의 의도와 목적에 맞나 |
| V-모델에서 | 단위·통합·시스템 테스트 (앞 단계 산출물과 대조) | 인수 테스트 (고객·사용자 요구와 대조) |
명세대로 정확히 만들었는데 사용자가 원한 것이 아니면 검증은 통과하고 확인은 실패한 것이다. 요구사항 단계의 검증은 요구사항 검증에 있다.
정적 기법과 동적 기법
| 구분 | 방법 | 대상 |
|---|---|---|
| 정적(static) | 실행하지 않고 사람이 읽거나(리뷰, 인스펙션, 워크스루) 도구로 분석한다(정적 분석) | 요구사항 명세서, 설계서, 소스 코드 등 모든 산출물 |
| 동적(dynamic) | 코드를 실행해 결과를 본다. 블랙박스·화이트박스 기법으로 케이스를 만든다 | 실행 가능한 코드 (단위~인수 테스트) |
정적 기법은 코드가 생기기 전 문서에도 쓸 수 있어 결함을 더 일찍 잡는다. 코드 리뷰 체크리스트에는 "명세의 기능이 다 반영됐나", "변수를 쓰기 전에 초기화했나", "무한 루프에 빠지는 조건이 있나" 같은 항목이 들어간다. 도구 기반 정적 분석은 정적 분석에 있다.
테스트 케이스 설계
가능한 입력을 전부 넣어 보는 것은 불가능하다. 테스트 설계는 어떤 입력을 고르면 적은 수로 많은 결함을 찾을 수 있는가를 정하는 일이다.
| 항목 | 내용 |
|---|---|
| ID | 명명 규칙을 따른 식별자 (TC_LOGIN_001) |
| 대상 요구사항 | 무엇을 검증하는가 |
| 사전 조건 | 실행 전에 갖춰야 할 환경·데이터 |
| 입력 값 | 넣을 값 |
| 예상 결과 | 정상이라면 나와야 할 값 |
| 실제 결과·판정 | 실행 후 기록. 다르면 결함 등록 |
설계 단계에는 케이스 외에 테스트 절차(어떤 순서로 실행할지)와 테스트 환경(대상 SW, 장비, 도구)도 정한다. 케이스를 뽑는 근거에 따라 기법이 갈린다.
| 구분 | 무엇을 보고 케이스를 뽑나 | 주로 쓰는 레벨 |
|---|---|---|
| 블랙박스(명세 기반) | 요구사항 명세서, 설계서. 입력과 출력만 본다 | 시스템·인수 테스트 |
| 화이트박스(구조 기반) | 소스 코드의 제어 흐름 | 단위 테스트 |
| 그레이박스 | 둘을 섞는다 (모듈 인터페이스는 명세로, 내부는 코드로) | 통합·시스템 테스트 |
블랙박스 테스트 (명세 기반)
내부 구조를 보지 않고 입력과 출력만으로 기능을 검증한다.
| 기법 | 설명 | 예 (0 ≤ x ≤ 10이 유효할 때) |
|---|---|---|
| 동등(동치) 분할 | 입력을 유효·무효 구간으로 나눠 구간마다 대표값 하나로 테스트 | 점수 구간마다 하나씩 |
| 경계값 분석 | 오류가 잦은 경계 근처 값으로 테스트 | -1, 0, 10, 11 |
| 신택스 | 입력 형식 규칙을 적합·부적합으로 나눠 테스트 | 길이·문자 종류 위반 값 |
| 결정 테이블 | 조건 조합과 그에 따른 동작을 표로 만들어 열마다 케이스 하나 | 회원 여부 × 쿠폰 여부 |
| 상태 전이 | 상태와 이벤트에 따른 전이를 모두(또는 무효 전이까지) 지나게 한다 | 로그인 3회 실패 → 잠금 |
| 원인-결과 그래프 | 입력(원인)과 출력(결과)의 관계를 그래프로 분석해 효율적인 케이스 선정 | - |
| 오류 예측 | 경험으로 오류가 날 만한 부분을 추측 | - |
| 비교 검사 | 여러 버전에 같은 입력을 주고 결과 비교 | - |
| 페어와이즈 | 모든 조합 대신, 입력 값들의 모든 쌍이 최소 한 번씩 등장하도록 조합해 적은 수의 테스트로 넓은 범위를 커버 | - |
아래는 주요 기법으로 실제 케이스를 뽑는 과정이다.
신택스 테스팅
입력의 형식 규칙을 적합(valid)과 부적합(invalid)으로 나눠 케이스를 만든다. 회원 가입의 이름 규칙이 "한글 2~8자"라면:
| 입력 | 분류 | 예상 결과 |
|---|---|---|
| 김하늘 | 적합 | 통과 |
| 김 | 부적합(길이 부족) | "2자 이상 입력하세요" |
| 김하늘7 | 부적합(숫자 포함) | "한글만 입력하세요" |
| (빈 값) | 부적합(Null) | "이름을 입력하세요" |
동등 분할
같은 동작이 예상되는 입력끼리 묶어(동등 클래스) 클래스마다 대표값 하나만 테스트한다. 영화 티켓 요금을 예로 든다.
| 변수 | 유효 클래스 | 무효 클래스 |
|---|---|---|
| 나이 | 0 | 음수, 숫자가 아닌 값 |
| 상영 시간대 | 조조, 일반, 심야 | 목록에 없는 값 |
변수가 여러 개일 때 모든 클래스를 한 번씩 덮는 최소 케이스 수는 클래스가 가장 많은 변수의 클래스 수다. 나이 4개, 시간대 3개이므로 4개면 된다.
| TC | 나이 | 시간대 | 예상 요금 |
|---|---|---|---|
| 1 | 3 | 조조 | 0원 |
| 2 | 12 | 일반 | 청소년 일반 요금 |
| 3 | 30 | 심야 | 성인 심야 요금 |
| 4 | 70 | 일반 | 경로 요금 |
동등 분할은 변수 사이의 조합은 보지 않는다. 조합이 중요하면 결정 테이블이나 페어와이즈를 쓴다.
경계값 분석
결함은 클래스의 경계에 몰린다(<와 <=를 헷갈리는 실수). 그래서 경계 근처 값을 고른다.
- 2-값 경계 분석: 경계마다 경계 값과, 바로 옆 다른 클래스의 값 하나.
- 3-값 경계 분석: 경계 값과 양옆 값 둘.
위 나이 예에서 경계는 0, 6/7, 18/19, 64/65다. 2-값으로 뽑으면 -1, 0, 6, 7, 18, 19, 64, 65다. 정수가 아니라 무게 같은 실수라면 "바로 옆 값"을 0.1이나 0.01처럼 요구사항의 정밀도에 맞춰 정한다.
결정 테이블
입력 조건과 결과가 참·거짓으로 나뉠 때, 조건의 조합을 표로 만들고 조합마다 케이스를 만든다. 쿠폰 적용을 예로 든다.
| 규칙 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 조건: 쿠폰이 유효한가 | T | T | T | F |
| 조건: 최소 주문 금액 충족 | T | T | F | - |
| 조건: 회원 전용 쿠폰에 회원인가 | T | F | - | - |
| 결과: 할인 적용 | ✔ | |||
| 결과: 거절 사유 | 회원 전용 | 금액 부족 | 만료·무효 |
-는 "무엇이든 결과가 같다"는 뜻이다. 조건 3개의 조합은 8개지만 결과가 같은 것을 합쳐 4개로 줄였다. 물리적으로 발생할 수 없는 조합(예: 상품명 검색과 상품 번호 검색을 동시에 선택)도 표에서 확인하고 지운다.
상태 전이 테스팅
시스템의 상태와 이벤트에 따른 전이를 보고 케이스를 뽑는다. 주문 상태를 예로 든다.
stateDiagram-v2 direction LR state "결제 대기" as waiting state "결제 완료" as paid state "배송 중" as shipping state "배송 완료" as delivered state "취소됨" as canceled waiting --> paid : 결제(t1) paid --> shipping : 발송(t3) shipping --> delivered : 수령(t5) waiting --> canceled : 취소(t2) paid --> canceled : 취소(t4)
얼마나 깊게 테스트할지는 전이 스위치 레벨로 정한다.
| 레벨 | 기준 | 케이스 |
|---|---|---|
| 스위치 0 | 전이 하나하나를 최소 한 번 | t1, t2, t3, t4, t5 (5개) |
| 스위치 1 | 연속된 전이 두 개의 모든 쌍 | t1→t3, t1→t4, t3→t5 (3개) |
레벨 N은 연속 전이 N+1개의 조합이다. 상태 전이도를 트리로 펼치면(전이 트리) 경로를 빠짐없이 뽑기 쉽다. 정의되지 않은 전이(배송 중에 취소 시도)가 거부되는지도 따로 확인한다.
시나리오 테스팅
실제 사용 흐름을 기본 흐름과 대체 흐름으로 나눠 케이스로 만든다. 유스케이스 명세가 있으면 정상·대안·예외 흐름의 조합이 그대로 시나리오가 된다(유스케이스 명세). ATM 예라면 "비밀번호 1회 틀린 뒤 성공", "3회 연속 틀려 거래 중지" 같은 흐름이 각각 하나의 케이스다. 시스템·인수 테스트에서 주로 쓴다.
페어와이즈 테스팅
모든 조합을 테스트할 수 없을 때, 임의의 두 변수 값 쌍이 최소 한 번씩 나오도록 조합을 고른다. 변수 A(A1, A2), B(B1, B2), C(C1, C2)의 전체 조합은 8개지만 페어와이즈로는 4개면 된다.
| TC | A | B | C |
|---|---|---|---|
| 1 | A1 | B1 | C1 |
| 2 | A1 | B2 | C2 |
| 3 | A2 | B1 | C2 |
| 4 | A2 | B2 | C1 |
A-B, A-C, B-C의 모든 쌍이 한 번 이상 등장한다. 결함 대부분은 변수 한두 개의 상호작용에서 생긴다는 경험에 기댄 방법이라, 셋 이상이 얽힌 결함은 놓칠 수 있다. 조합은 손으로 짜지 않고 Microsoft의 PICT 같은 도구로 생성한다.
어떤 기법을 고를까
| 요구사항의 모양 | 기법 |
|---|---|
| 입력 형식 규칙이 있다 (길이, 문자 종류) | 신택스 |
| 값의 구간마다 동작이 다르다 | 동등 분할 + 경계값 |
| 여러 조건의 조합이 결과를 정한다 | 결정 테이블 |
| 상태가 있고 이벤트로 바뀐다 | 상태 전이 |
| 사용 흐름 전체를 검증한다 | 시나리오 |
| 설정·환경 변수가 많아 조합이 폭발한다 | 페어와이즈 |
화이트박스 테스트 (구조 기반)
내부 논리 구조를 보고 실행 경로를 확인한다. 코드의 모든 경로를 실행하는 것은 반복문 하나만 있어도 불가능하므로, 어디까지 실행하면 충분한가를 정하는 기준이 커버리지다. 코드를 노드(실행·분기)와 간선(흐름)으로 그린 제어 흐름 그래프(CFG) 위에서 센다.
| 기준 | 의미 |
|---|---|
| 구문(문장) 커버리지 | 모든 문장을 최소 한 번 실행 |
| 결정(분기) 커버리지 | 각 결정문 전체가 참·거짓을 최소 한 번씩 |
| 조건 커버리지 | 결정문 안의 개별 조건식이 참·거짓을 최소 한 번씩 |
| 조건/결정 커버리지 | 위 두 가지를 모두 만족 |
| MC/DC | 각 개별 조건이 결과에 독립적으로 영향을 주는지 확인 |
| 다중 조건 커버리지 | 개별 조건의 참·거짓 모든 조합을 실행. 가장 강하지만 케이스가 2ⁿ개 |
기초 경로 검사, 제어 흐름 검사, 데이터 흐름 검사 등도 화이트박스 기법이다. 기초 경로 검사는 CFG의 McCabe 순환 복잡도 V(G) = E - N + 2만큼 선형 독립 경로를 뽑아 각 경로를 지나는 케이스를 만든다. 순환 복잡도 계산은 복잡도 척도에 있다. 데이터 흐름 검사는 변수가 정의된 곳과 쓰이는 곳을 이어 그 경로를 지나게 한다. 기준 사이의 강약은 다음과 같다(화살표 방향으로 강해진다).
flowchart LR fn["함수"] --> st["문장"] --> br["분기(결정)"] --> bc["분기/조건"] --> mcdc["MC/DC"] --> mcc["다중 조건"] cond["조건"] --> bc
조건 커버리지는 문장·분기와 강약을 비교할 수 없어서 따로 표시했다. 아래 예제를 보면 이유가 보인다.
예제 하나로 비교하기
function shippingFee(total: number, isMember: boolean): number {
let fee = 3000;
if (total >= 50000 && isMember) { // 조건 A: total >= 50000, 조건 B: isMember
fee = 0;
}
return fee;
}| 기준 | 요구 | 최소 케이스 (A, B → 결정) |
|---|---|---|
| 문장 | 모든 문장을 한 번 이상 | (T, T → T) 1개 |
| 분기(결정) | 결정 전체가 참·거짓을 한 번씩 | (T, T → T), (F, T → F) |
| 조건 | 개별 조건이 각각 참·거짓을 한 번씩 | (T, F → F), (F, T → F) |
| 분기/조건 | 분기와 조건을 모두 만족 | (T, T → T), (F, F → F) |
| MC/DC | 각 조건이 혼자서 결정을 바꾸는 것을 보인다 | (T, T → T), (F, T → F), (T, F → F) |
| 다중 조건 | 조건의 모든 조합 | 4개 |
조건 커버리지 행을 보면, A와 B가 각각 참·거짓을 다 가졌는데도 결정은 한 번도 참이 되지 않았다. 조건 100%가 분기 100%를 보장하지 않는다. 반대로 분기 100%도 조건 100%를 보장하지 않는다. 그래서 둘을 합친 분기/조건 커버리지가 있다.
MC/DC가 잡는 실수
개발자가 &&를 ||로 잘못 썼다고 하자.
| 입력 (A, B) | 올바른 코드 && | 잘못된 코드 || |
|---|---|---|
| (T, T) | 무료 | 무료 |
| (F, F) | 유료 | 유료 |
| (F, T) | 유료 | 무료 |
분기/조건 커버리지를 채운 (T, T), (F, F)로는 두 코드가 똑같이 통과한다. MC/DC는 "B를 참으로 고정하고 A만 바꿔 결정이 바뀌는지" 보려고 (F, T)를 반드시 포함하므로 이 실수를 잡는다. 조건 N개에 대해 보통 N+1개 케이스로 충족되어, 2^N개가 필요한 다중 조건보다 훨씬 싸다. 항공·자동차 같은 안전 필수 분야 표준이 최고 등급에서 MC/DC 100%를 요구하는 이유다(소프트웨어 안전 표준).
커버리지를 쓸 때 주의할 것
- 커버리지는 실행했는가만 센다. 결과를 검증(assert)하지 않은 테스트도 커버리지는 올린다.
- 100%를 목표로 삼기보다, 위험이 큰 모듈일수록 더 강한 기준을 거는 식으로 나눈다(아래 「위험 기반 테스트」).
- 측정은 도구에 맡긴다. Java는 JaCoCo(Eclipse 플러그인 EclEmma), JavaScript는 Istanbul 계열(Jest·Vitest의 coverage 옵션)이 문장·분기 커버리지를 보고한다.
테스트 오라클
테스트 결과가 맞는지 판단하기 위해 미리 정의한 기대값(참 값) 을 대입해 비교하는 기법.
| 종류 | 설명 |
|---|---|
| 참(True) 오라클 | 모든 입력에 대해 기대 결과 제공 → 모든 오류 검출 가능 |
| 샘플링 오라클 | 특정 몇몇 입력에 대해서만 기대 결과 제공 (경계값·구간 대표값 등) |
| 추정(Heuristic) 오라클 | 일부는 기대 결과를 주고 나머지는 추정 |
| 일관성 오라클 | 변경 전후의 결과를 비교 |
통합 테스트와 테스트 하네스
| 방식 | 진행 방향 | 필요한 가짜 모듈 |
|---|---|---|
| 상향식 | 최하위 모듈부터 위로 | 테스트 드라이버 (상위 모듈 역할, 하위 모듈을 호출) |
| 하향식 | 최상위 모듈부터 아래로 | 테스트 스텁 (아직 없는 하위 모듈 대신 간단히 응답) |
| 샌드위치 | 상향식 + 하향식 | 둘 다 |
| 빅뱅 | 한꺼번에 통합 | 없음 (오류 위치 찾기 어려움) |
테스트 하네스는 테스트를 돕는 코드와 데이터의 모음이다: 테스트 드라이버, 테스트 스텁, 테스트 케이스, 테스트 슈트(케이스 묶음), 테스트 스크립트, 목 오브젝트. 목(Mock) 객체는 의존하는 부분을 고립시키려고 미리 행위를 정해 둔 가짜 객체다. 더미·스텁·스파이·페이크·목의 차이는 프론트엔드 테스트의 종류와 도구에 있다.
테스트 프로세스
테스트 기법을 아는 것과 테스트를 체계적으로 운영하는 것은 다른 문제다. 무엇을 얼마나 테스트할지 계획하고, 진행을 측정하고, 끝낼 시점을 정하고, 다음 프로젝트에서 더 잘하는 것까지가 테스트 프로세스다. 큰 순서는 PDCA다: 계획(범위·일정·전략) → 설계(케이스와 절차) → 수행(실행과 모니터링·제어) → 평가·개선.
ISO/IEC/IEEE 29119의 세 계층
국제 테스트 표준 ISO/IEC/IEEE 29119는 테스트 프로세스를 세 계층으로 나눈다. 위 계층이 아래 계층의 틀을 정하고, 아래 계층의 결과가 위로 피드백된다.
flowchart TB
subgraph org["조직 계층"]
direction LR
o1["테스트 정책·전략 수립"] --> o2["활용 모니터링"] --> o3["개선"]
end
subgraph mgr["관리 계층"]
direction LR
m1["테스트 계획"] --> m2["모니터링·제어"] --> m3["테스트 완료"]
end
subgraph dyn["동적 테스트 계층"]
direction LR
d1["설계·구현"] --> d2["환경 구성·유지"] --> d3["실행"] --> d4["결과(결함) 보고"]
end
org -->|"정책·전략"| mgr
mgr -->|"계획·제어 지시"| dyn
dyn -->|"측정값"| mgr
mgr -->|"피드백"| org| 계층 | 범위 | 주요 산출물 |
|---|---|---|
| 조직 | 회사·조직 전체 | 테스트 정책 명세서, 조직 테스트 전략 명세서 |
| 관리 | 프로젝트, 또는 단계별(단위·통합·시스템·인수)·유형별(성능·보안) | 테스트 계획서, 상태 보고서, 완료 보고서 |
| 동적 테스트 | 실제로 테스트를 돌리는 일 | 테스트 명세서, 테스트 환경, 결과 기록, 결함 보고서 |
테스트 계획과 완료 기준
계획은 대략 다음 순서로 세운다: 맥락(범위·일정) 파악 → 위험 식별·분석 → 위험 완화 방법 → 테스트 전략 설계 → 인력·일정 결정 → 계획서 작성 → 이해관계자 합의 → 공유.
계획서에 꼭 들어갈 것은 완료 기준이다. "언제 테스트를 끝낸다고 말할 수 있나"를 미리 숫자로 정해 둔다.
| 레벨 | 완료 기준 예 | 산출식 |
|---|---|---|
| 단위 | 문장 커버리지 80%, 분기 커버리지 70% | 실행한 문장(분기) 수 ÷ 전체 문장(분기) 수 |
| 시스템 | 요구사항 커버리지 100% | 테스트한 요구사항 수 ÷ 전체 요구사항 수 |
| 공통 | 치명·주요 결함 미해결 0건 | - |
모니터링·제어 지표
진행 중에는 측정값을 계획과 비교해 늦거나 어긋난 곳을 고친다.
| 지표 | 계산 |
|---|---|
| 테스트 진척률 | 실행한 케이스 수 ÷ 전체 케이스 수 |
| 테스트 케이스 실패율 | 실패한 케이스 수 ÷ 전체 케이스 수 |
| 테스트 케이스 효율성 | 발견한 결함 수 ÷ 실행한 케이스 수 |
| 결함 조치율 | 조치 완료 결함 수 ÷ 전체 결함 수 |
| 심각도별·유형별·발견 단계별 분포 | 해당 결함 수 ÷ 전체 결함 수 |
| 평균 결함 수 | 결함 수 ÷ 테스트 대상 모듈 수 |
위험 기반 테스트
테스트 자원은 늘 부족하다. 위험 기반 테스트는 기능마다 위험 크기를 매기고, 위험이 큰 곳에 더 많은 자원과 더 강한 기법을 쓰는 전략이다. 위험의 정의, 식별·분석 절차, 회피·완화·전가·수용의 대응 유형은 프로젝트 위험 관리와 같고, 테스트에서는 두 축을 이렇게 판단한다.
| 축 | 판단 근거 |
|---|---|
| 발생 확률 (결함이 있을 가능성) | 코드 복잡도, 모듈 간 상호작용, 구현 기술의 난이도, 코드 규모, 담당 개발자의 숙련도 |
| 영향도 (고장 시 피해) | 사용 빈도, 사용자에게 중요한 정도, 금전·안전 피해, 대외 이미지 |
위험 크기 = 발생 확률 × 영향도. 쇼핑몰이라면 다음처럼 기능별 단위 테스트 기준이 갈린다.
| 기능 | 확률(1~5) | 영향(1~5) | 위험 크기 | 단위 테스트 기준 |
|---|---|---|---|---|
| 결제 | 4 | 5 | 20 | MC/DC 100% + 경계값 |
| 로그인 | 3 | 5 | 15 | MC/DC 100% |
| 상품 검색 | 4 | 3 | 12 | 분기·조건 100% |
| 장바구니 | 3 | 3 | 9 | 분기 100% |
| 리뷰 작성 | 2 | 2 | 4 | 문장 100% |
| 공지사항 | 1 | 1 | 1 | 문장 100% |
quadrantChart x-axis "발생 확률 낮음" --> "발생 확률 높음" y-axis "영향도 낮음" --> "영향도 높음" quadrant-1 "① 둘 다 높음, 가장 강한 기준 (결제)" quadrant-2 "③ 확률 낮고 영향 큼 (로그인)" quadrant-3 "④ 둘 다 낮음 (공지사항, 리뷰)" quadrant-4 "② 확률 높고 영향 작음 (상품 검색)"
이렇게 하면 "모든 기능을 똑같이 꼼꼼하게"라는 불가능한 목표 대신, 기능마다 근거 있는 완료 기준이 생긴다. 요구사항마다 여러 위험 요인(정전, 파일 손상, 무단 접근, DB 불일치, 느린 처리 등)별로 점수를 매기고 합산해 우선순위를 정하는 방법도 있다.
평가와 개선
테스트가 끝나면 두 방향으로 돌아본다.
- 효과성: 테스트로 결함을 얼마나 많이 찾았나 (실패율, 단계별 결함 발견 비율).
- 효율성: 그 효과를 얻는 데 비용(공수)이 얼마나 들었나 (공수당 발견 결함 수).
결과를 보고 계획·설계·실행 중 어디를 바꿀지 정한다. 조직의 테스트 프로세스 역량 자체를 평가하는 표준으로 ISO/IEC 33063이 있다. 결함 조치율은 조직의 품질 수준을 보여 주는 지표로 자주 쓰인다. Capers Jones의 조사(2000)에서는 평균적인 조직이 7585%, 상위 조직이 9095%였고, 일부 대기업은 99% 수준이었다.
테스트 자동화
자동화는 프로세스의 반복적이고 실수하기 쉬운 부분을 도구에 맡기는 것이다. 자주 반복하지 않는 테스트는 도구를 만드는 비용이 더 커서 자동화할 이유가 없다.
| 영역 | 자동화하는 일 | 도구 예 |
|---|---|---|
| 설계 | 기법을 적용해 케이스를 생성한다 | 페어와이즈 조합 생성(PICT) |
| 환경 | 환경 구성을 코드로 재현한다 (IaC). "내 PC에서는 됐는데" 문제를 줄인다 | Docker, Terraform |
| 실행 | 케이스 실행과 결과 판정(assert)을 반복한다. 데이터 주도, 키워드 주도 방식이 있다 | Selenium, Playwright, xUnit 계열 |
| 정적 분석 | 프로그램을 실행하지 않고 코딩 표준·스타일·복잡도·결함을 분석 | 린터, 정적 분석기 |
| 성능 | 가상 사용자로 처리량·응답 시간 등을 측정 | 부하 테스트 도구 |
| 통제 | 테스트·형상·결함 관리 | 이슈·테스트 관리 시스템 |
브라우저 조작을 녹화해 재생하는 방식(Selenium IDE)은 시작은 쉽지만, 화면 구조가 바뀌면 깨지기 쉽다. 오래 유지할 테스트는 코드로 쓴다. 단계별 자동화 설계는 테스트 실행 단계, 환경 구성은 Dockerfile, Terraform 워크플로에 있다.
애플리케이션 성능 지표
- 처리량: 일정 시간에 처리하는 트랜잭션 수
- 응답 시간: 요청 입력이 끝난 후 응답 출력이 시작될 때까지
- 경과 시간: 요청 시점부터 처리 결과 출력이 끝날 때까지
- 자원 사용률: 처리 중 사용하는 CPU·메모리·네트워크 사용량
결함 관리
- 결함 생명 주기: 등록 → 검토 → 할당 → 수정 → 재테스트(확인) → 종료. 재테스트에서 다시 실패하면 할당으로 돌아가고, 재등록·조치 보류도 가능하다.
- 결함 보고서 한 장에 담을 것: ID, 관련 기능, 재현 방법과 예상·실제 결과, 조치 제안, 심각도와 그 근거, 처리 상태.
- 결함 분석: 구체화, 고립화, 일반화
- 결함 추이 분석: 결함 분포, 결함 추세, 결함 에이징
- 결함 심각도: 치명적 > 주요 > 보통 > 경미 > 단순 (외우기: 치주보경단)
- 결함 우선순위: 결정적 > 높음 > 보통 > 낮음
테스트를 먼저 쓰고 구현하는 실무 방식은 프론트엔드에서의 TDD에 정리했다.
AI 소프트웨어 테스트
일반 소프트웨어는 사람이 규칙을 코드로 쓰고, 그 규칙이 맞는지 테스트한다(연역). AI 소프트웨어는 데이터에서 규칙을 배우고, 배운 모델로 처음 보는 입력을 판단한다(귀납). 규칙이 코드에 적혀 있지 않으니 "이 입력이면 이 출력"을 미리 다 정하기 어렵고, 위의 기법이 그대로 통하지 않는다. AI가 낸 고장도 시스템을 거쳐 사고로 이어진다. 2018년 우버 자율주행 시험차의 보행자 사망 사고가 그런 예다.
AI 소프트웨어의 추가 품질 특성
AI 소프트웨어도 ISO/IEC 25010 품질 특성을 만족해야 하고, 거기에 고유한 특성이 더해진다. 정보통신산업진흥원(NIPA)의 「중소SW기업 SW품질관리 가이드 – AI 시스템 테스트」(2019)는 다음처럼 분류한다.
| 특성 | 뜻 | 테스트에서 신경 쓸 점 |
|---|---|---|
| 적응성 | 새 환경·데이터에 맞춰 동작을 바꾼다 | 바뀐 뒤에도 요구사항을 지키는지 |
| 자율성 | 사람 개입 없이 스스로 판단한다 | 사람이 개입해야 할 경계가 지켜지는지 |
| 진화 | 재학습으로 시간이 지나며 변한다 | 버전마다 회귀가 없는지 |
| 유연성 | 예상하지 못한 입력에도 대응한다 | 학습 분포 밖 입력에서의 동작 |
| 편향성 | 데이터의 치우침이 결과에 스며든다 | 집단별 성능 차이(데이터 편향) |
| 성능 지표 | 정확도, 정밀도, 재현율 같은 통계 지표로 품질을 잰다 | 목표 수치와 평가 데이터(분류 모델 성능 평가 지표) |
| 투명성 | 왜 그런 판단을 했는지 설명할 수 있는가 | 설명 가능성 요구 여부 |
| 복잡성 | 추론 과정이 사람이 따라가기 어렵다 | 기대 결과(오라클)를 만들기 어렵다 |
| 비결정성 | 같은 입력에도 결과가 달라질 수 있다 | 반복 실행, 허용 오차 |
AI 부분의 V-모델
"제품의 품질은 그것을 만드는 프로세스의 품질이 정한다"는 원칙은 AI에도 적용된다. AI 부분은 V-모델 안에 별도의 작은 흐름으로 들어간다.
flowchart TB
sr["시스템 요구사항 분석"] --> sa["시스템 아키텍처 설계"]
subgraph ai["AI 부분"]
ar["요구사항 분석"] --> dp["훈련 데이터 준비"] --> tr["훈련"] --> et["평가 데이터 기반 테스트"] --> mt["훈련 완료 모델 테스트"]
dp -.- et
ar -.- mt
end
subgraph sw["일반 SW 부분"]
rq["요구사항"] --> ds["설계"] --> im["구현"] --> ut["단위·통합 테스트"]
end
sa --> ar
sa --> rq
mt --> it["통합 테스트"]
ut --> it
it --> at["시스템·인수 테스트"]
sa -.- it
sr -.- at| 단계 | 할 일 | 예 (고양이 사진 분류) |
|---|---|---|
| 요구사항 분석 | 문제를 정의하고 AI 품질 특성을 반영한다 | 고양이 여부만인가, 품종까지인가? 얼굴 사진인가 전신인가? 정확도·재현율 목표는? |
| 훈련 데이터 준비 | 요구사항을 만족할 데이터셋을 설계하고 모은다 | 품종·자세·조명별로 고르게 수집하고 라벨을 검수한다 |
| 훈련 | 모델을 고르고 학습한다 | - |
| 평가 데이터 기반 테스트 | 학습에 쓰지 않은 데이터로 성능을 잰다 | 미달이면 모델 선택, 하이퍼파라미터, 데이터 양을 다시 본다 |
| 훈련 완료 모델 테스트 | 시스템에 넣은 상태로 요구사항을 검증한다 | 성능이 높게 나와도 운영 중 계속 테스트한다 |
AI 부분에서는 데이터 품질이 곧 제품 품질이다. 편향되거나 라벨이 틀린 데이터는 코드를 아무리 잘 짜도 고칠 수 없다(데이터 파이프라인 기초).
전통 기법이 잘 안 맞는 이유
동등 분할은 "같은 클래스의 입력은 같게 동작한다"는 가정에 기댄다. 성적을 등급으로 바꾸는 AI 모델이라면, 사람이 짠 코드처럼 90~100점 구간에서 95점 하나만 확인해서는 안 된다. 모델은 학습 데이터에 없던 93점에서 엉뚱한 등급을 낼 수 있다. 구간 안의 동작이 균일하다는 보장이 없다. 또 출력이 확률적이라 정답을 미리 정하는 테스트 오라클 문제가 커진다.
AI 테스트 기법
| 구분 | 기법 | 아이디어 | 예 |
|---|---|---|---|
| 블랙박스 | 조합 테스팅 | 입력 속성(날씨, 조명, 물체 종류)의 조합을 체계적으로 만든다 | 페어와이즈로 시나리오 조합 생성 |
| 블랙박스 | 백투백 테스팅 | 같은 입력을 여러 모델·버전에 넣고 결과를 비교한다 | 새 모델과 기존 모델의 판정이 갈리는 입력을 집중 분석 |
| 블랙박스 | 변성(Metamorphic) 테스팅 | 정답은 몰라도 입력을 이렇게 바꾸면 출력은 이래야 한다는 관계로 검증한다 | 사진을 살짝 회전하거나 밝기를 바꿔도 분류는 같아야 한다. 주행 영상에 비를 합성해도 조향 각도는 비슷해야 한다 |
| 블랙박스 | 탐색적 테스팅 | 학습 때 몰랐던 경우를 찾아 반복적으로 파고든다 | 입력 영역 정의 → 케이스 생성 → 시뮬레이션 → 결과 확인 → 결함이면 수정 후 재실행 |
| 화이트박스 | 뉴런 커버리지 | 테스트 데이터로 활성화된 뉴런의 비율. 비활성 뉴런을 깨우는 입력을 데이터셋에 추가한다 | - |
| 화이트박스 | 임계점·부호 변경·값 변경 커버리지 | 활성값이 임계값을 넘거나, 부호가 바뀌거나, 크게 바뀌는 경우를 덮었는가 | - |
변성 테스팅이 특히 쓸모 있다. 오라클이 없어도 관계만 정하면 테스트를 만들 수 있기 때문이다. 같은 발상은 LLM 기능에도 통한다. 질문의 표현만 바꿔도 답의 핵심은 같아야 한다는 식이다(평가 주도 개발).
뉴런 커버리지는 코드 커버리지를 신경망에 옮긴 발상이다(퍼셉트론과 다층 신경망). 다만 뉴런 커버리지가 높을수록 결함을 더 잘 찾는지는 연구자들 사이에서 논란이 있어 참고 지표로 본다.
가상 환경 테스트: 디지털 트윈
자율주행이나 로봇처럼 실제 환경에서 테스트하기 위험하거나 비싼 경우, 실물을 디지털로 복제한 디지털 트윈에서 시뮬레이션으로 테스트한다. 실제로 재현하기 어려운 예외 상황(보행자 돌발 출현, 폭우, 센서 고장)을 안전하게 시험하고, 여러 환경을 병렬로 돌리고, 장비와 현장 비용을 줄인다. 시뮬레이션과 현실의 차이는 남으므로, 시뮬레이션에서 찾은 위험 시나리오를 실제 시험으로 확인하는 단계를 둔다.
정리
- 품질 기준은 ISO/IEC 25010, 테스트 레벨은 V-모델, 검증은 명세 대조, 확인은 사용자 의도 대조다.
- 테스트와 QC는 제품을, QA와 감사는 프로세스를 본다. 시스템 테스트는 기능·성능(부하·스트레스)·보안·이식성·복구로 나눠 한다.
- 블랙박스 기법은 요구사항의 모양(형식 규칙, 구간, 조건 조합, 상태, 흐름, 조합 폭발)에 맞춰 고른다.
- 커버리지는 문장 < 분기 < 분기/조건 < MC/DC < 다중 조건 순으로 강해지고, 조건 커버리지는 분기를 보장하지 않는다.
- 테스트는 29119의 조직·관리·동적 계층으로 운영하고, 완료 기준을 숫자로 정하고, 위험 크기에 따라 강도를 나눈다.
- AI 소프트웨어는 오라클을 만들기 어려워 변성·백투백처럼 관계와 비교로 검증한다.
관련 노트: 프론트엔드 테스트의 종류와 도구, 정적 분석: 실행하지 않고 검사하기, 의존성이 있는 컴포넌트 테스트하기, 백엔드 테스트, 소프트웨어 설계와 공학, 소프트웨어 안전, 머신러닝 기초, CI/CD