본문으로 건너뛰기
입문22

검증과 확인, 오류·결함·실패의 구분과 전파

제대로 만들고 있는가(검증)와 맞는 것을 만들고 있는가(확인)를 구분하고, 사람의 실수가 결함을 거쳐 실패로 드러나는 경로를 코드로 추적한다.

  • #검증
  • #확인
  • #결함전파
  • #QA기초

개념

검증(Verification) vs 확인(Validation)

두 단어가 한국어로도 영어로도 헷갈리기 쉬운데, 질문 형태로 외우면 구분이 쉽다.

질문확인 대상시점
검증 (Verification)"우리가 제대로 만들고 있는가?"산출물이 명세·설계와 일치하는가개발 각 단계마다 (문서, 설계, 코드)
확인 (Validation)"우리가 맞는 것을 만들고 있는가?"실제로 사용자 요구를 충족하는가보통 동작하는 소프트웨어로, 더 나중에

검증은 "명세대로 만들었는가"를 보고, 확인은 "그 명세 자체가 맞았는가, 실제로 쓸모 있는가"를 본다. 이 둘은 독립적으로 실패할 수 있다.

  • 검증은 통과, 확인은 실패: 명세에 적힌 대로 정확히 만들었지만, 명세 자체가 사용자의 실제 흐름과 안 맞아서 아무도 못 쓴다.
  • 검증은 실패, 확인은 (우연히) 통과: 명세와 다르게 만들었는데, 그게 오히려 사용자에게 더 자연스러워서 아무도 불만을 못 느낀다. (드물지만 일어난다 — 이 경우 명세를 갱신해야 한다는 신호다.)

코드 리뷰, 단위 테스트, 명세 대조는 검증에 가깝고, 사용자 인수 테스트(UAT), 베타 테스트, 실사용자 피드백은 확인에 가깝다.

오류 → 결함 → 실패의 전파

세 단어를 QA에서는 엄격하게 구분한다.

  • 오류(Error): 사람이 저지른 실수. 요구사항을 잘못 이해했거나, 코드를 잘못 짰거나.
  • 결함(Defect/Fault): 그 실수가 산출물(코드, 문서, 설계)에 남긴 흔적. 아직 실행되지 않았을 수도 있다.
  • 실패(Failure): 그 결함이 특정 조건에서 실행되어 겉으로 드러난 오작동.
// 오류: 개발자가 "빈 배열도 유효한 입력"이라는 걸 놓쳤다 (사람의 실수)
function getDiscountRate(items) {
  // 결함: items가 빈 배열일 때를 고려하지 않은 코드가 여기 남아 있다
  return items[0].price > 100000 ? 0.1 : 0.05;
}
 
getDiscountRate([{ price: 150000 }]); // 0.1 — 정상 동작, 실패가 드러나지 않는다
getDiscountRate([]);                  // TypeError — 여기서 실패가 발생한다

이 코드는 결함이 있어도 대부분의 입력에서는 실패하지 않는다. 빈 배열이 들어오는 경로를 실행해야만 실패로 드러난다. 그래서 "지금까지 문제가 없었다"는 "결함이 없다"는 뜻이 아니라 **"그 결함을 건드리는 조건을 아직 실행해보지 않았다"**는 뜻일 수 있다.

이 전파 경로(오류 → 결함 → 실패)를 알면 결함 리포트를 쓸 때도 도움이 된다 — "무엇이 실패했는가"뿐 아니라 "어떤 조건이 그 결함을 건드렸는가"까지 적어야 재현과 수정이 빨라진다. 결함 리포트 작성법은 모듈 6에서 자세히 다룬다.

실무에서 왜 필요한가

실무에서 가장 흔한 오해는 "명세대로 만들었으니 QA 책임은 끝났다"는 생각이다. 하지만 명세 자체가 틀렸다면(확인 실패), 그건 QA가 검증만 하고 확인을 건너뛰었기 때문일 수 있다. 예를 들어 결제 폼이 요구사항 문서와 한 글자도 다르지 않게 구현됐지만(검증 통과), 실제 사용자 테스트에서 결제 단계가 너무 복잡해 다들 중간에 이탈한다면(확인 실패), 그 결함은 테스트 케이스로는 절대 못 잡는다 — 실제 사용자 흐름을 봐야 잡힌다.

또한 "결함이 있어도 실패가 안 보이면 괜찮다"는 생각도 위험하다. 위 코드 예시처럼, 결함은 그대로 남아있다가 몇 달 뒤 특정 이벤트(예: 프로모션으로 빈 장바구니 관련 로직이 새로 실행되는 경로)에서 갑자기 실패로 터지는 경우가 실무에서 자주 있다.

실습 과제

과제 1 — 검증인가 확인인가 (10분)

다음 활동이 검증(Verification)인지 확인(Validation)인지 분류한다.

  1. 설계 문서와 실제 구현된 API 응답 필드가 일치하는지 대조한다.
  2. 실제 사용자 5명에게 신규 가입 흐름을 써보게 하고 어디서 헤매는지 관찰한다.
  3. 요구사항 문서의 각 항목이 테스트 케이스로 하나씩 커버되는지 추적표로 확인한다.
  4. 베타 사용자 그룹에 기능을 먼저 공개하고 실제 사용 데이터를 본다.

과제 2 — 전파 경로 추적하기 (10분)

아래 코드에서 오류·결함·실패를 각각 찾아 적는다. "이 결함이 실패로 드러나려면 어떤 입력이 필요한가?"도 함께 적는다.

def calculate_average(scores):
    total = sum(scores)
    return total / len(scores)

자가 체크리스트

  • 검증과 확인을 각각 질문 형태("제대로 만들고 있는가" / "맞는 것을 만들고 있는가")로 설명할 수 있다
  • 검증은 통과하지만 확인은 실패하는 사례를 스스로 만들 수 있다
  • 오류·결함·실패 세 단어를 순서대로, 서로 다른 개념으로 구분해 쓸 수 있다
  • "결함이 있어도 실패가 관찰되지 않을 수 있다"는 이유를 코드 예시로 설명할 수 있다
  • 결함 리포트에 "어떤 조건이 결함을 건드렸는가"를 왜 적어야 하는지 설명할 수 있다

흔한 실수

  • 검증과 확인을 뒤바꿔 쓴다. "확인 테스트"라고 부르면서 실제로는 명세 대조(검증)만 하는 경우가 흔하다. 실제 사용자 관점이 빠졌다면 확인이 아니다.
  • "버그가 안 보인다 = 결함이 없다"고 결론짓는다. 실행되지 않은 코드 경로에 결함이 잠들어 있을 수 있다. 커버리지(모듈 3, 10에서 다룸)가 낮으면 이 위험이 커진다.
  • 오류의 책임을 개인에게 돌리는 데 집중한다. 오류는 사람이 만들지만, 결함이 실패로 이어지기까지 여러 단계(리뷰, 테스트)를 통과했다는 뜻이기도 하다. "누가 실수했나"보다 "왜 이 단계들에서 못 잡았나"가 더 생산적인 질문이다.

참고 자료

  • ISTQB Glossary — Verification / Validation — 공식 용어 정의
  • Barry Boehm, Software Engineering Economics — "Are we building the product right? / Are we building the right product?" 표현의 원출처로 자주 인용된다