본문으로 건너뛰기
입문약 20분

테스트 유형 — 기능·비기능·회귀·확인

무엇을 하는가와 얼마나 잘 하는가를 구분하고, 수정 후 재테스트를 확인 테스트와 회귀 테스트로 나눠 설계한다.

  • #테스트유형
  • #기능테스트
  • #비기능테스트
  • #회귀테스트
  • #확인테스트

개념

레벨과 유형은 서로 다른 축이다

레슨 3에서 배운 테스트 레벨은 "어느 범위를 함께 실행해서" 확인하는가였다. 단위·통합·시스템·인수. 이번 레슨의 테스트 유형은 "무엇을" 확인하는가다.

둘은 같은 줄에 놓고 고르는 선택지가 아니다. 동시에 정해지는 두 개의 좌표다. "결제 화면을 테스트한다"는 말만으로는 아무것도 정해지지 않는다. 실무의 테스트 계획서 한 줄은 항상 이 두 좌표를 같이 갖는다.

기능 유형비기능 유형
단위 레벨할인 계산 함수가 정확한 금액을 돌려주는가그 함수가 10만 건을 처리하는 데 몇 초 걸리는가
시스템 레벨로그인부터 결제까지 흐름이 끝나는가동시 접속 1,000명에서 결제가 5초 안에 끝나는가

표의 네 칸이 전부 서로 다른 테스트다. 레벨을 골랐다고 유형이 정해지지 않고, 유형을 골랐다고 레벨이 정해지지 않는다. 이 감각을 잡는 것이 이 레슨의 첫 목표다.

말버릇으로 굳혀두면 편하다 — 테스트를 하나 설계할 때마다 속으로 두 문장을 완성해본다. "어느 범위에서 돌리는가", "무엇을 확인하는가."

기능 테스트 — 무엇을 하는가

기능 테스트(Functional Testing) 는 소프트웨어가 하기로 되어 있는 일을 하는가를 본다. 판단 기준은 요구사항·기획서·사용자 스토리에 적힌 동작 그 자체다.

  • 로그인 버튼을 누르면 로그인이 되는가
  • 3만원 이상 주문에 배송비가 0원으로 계산되는가
  • 잘못된 비밀번호를 5회 입력하면 계정이 잠기는가
  • 품절 상품은 장바구니에 담기지 않는가

기능 테스트의 결과는 대체로 맞다/틀리다로 딱 떨어진다. 기대 결과가 "9,000원"인데 "9,000원"이 나오면 통과, "10,000원"이 나오면 실패다. 여기에는 해석의 여지가 거의 없다.

QA가 하는 일의 가장 큰 덩어리가 여기이고, 스테이지 2의 테스트 설계 기법(모듈 3의 동등분할·경계값·결정표 같은 것)은 대부분 기능 테스트 케이스를 효율적으로 뽑는 방법이다.

비기능 테스트 — 얼마나 잘 하는가

비기능 테스트(Non-functional Testing) 는 같은 기능을 놓고 얼마나 잘 하는가를 묻는다. 기능은 정확히 동작하는데도 쓸 수 없는 제품이 되는 지점이 여기다.

레슨 1에서 "품질은 하나의 값이 아니라 여러 축의 묶음"이라고 했던 것을 떠올려보자. 그때 이름만 스쳤던 ISO/IEC 25010의 갈래들이 바로 비기능 테스트의 목록이다.

핵심 차이는 합격선이 숫자로 정해져야 한다는 점이다. 기능 테스트는 "된다/안 된다"로 끝나지만, 비기능 테스트는 "3초 안에 응답한다"처럼 기준선이 없으면 판정 자체가 불가능하다. "좀 느린 것 같아요"는 결함 리포트가 아니라 감상이다.

비기능의 갈래 — 맛보기

각 갈래는 스테이지 5(모듈 16 비기능 테스트 종합)에서 도구와 함께 제대로 다룬다. 지금은 "이런 질문들이 따로 있다" 는 목록만 머리에 넣어두면 충분하다.

갈래한 줄로 하면 이런 질문실패했을 때 보이는 모습
성능(Performance)평소 조건에서 얼마나 빨리 응답하는가검색 결과가 8초 뒤에 뜬다
부하(Load)예상 최대 사용자 수를 견디는가티켓 오픈 10분간 접속이 안 된다
스트레스(Stress)한계를 넘겼을 때 어떻게 무너지고 어떻게 복구되는가트래픽이 빠진 뒤에도 서버가 안 돌아온다
보안(Security)권한 없는 사람이 못 하게 막혀 있는가남의 주문번호를 URL에 넣으면 남의 주소가 보인다
사용성(Usability)처음 쓰는 사람이 헤매지 않고 끝낼 수 있는가기능은 있는데 아무도 못 찾는다
신뢰성(Reliability)오래 돌려도 죽지 않는가, 죽으면 되살아나는가3일째 되는 날마다 메모리가 차서 재시작된다
호환성(Compatibility)다른 브라우저·기기·OS 버전에서도 되는가iOS 16에서만 결제 버튼이 안 눌린다
접근성(Accessibility)스크린리더·키보드만으로도 쓸 수 있는가키보드 탭으로 결제까지 못 간다

스크린리더 는 화면의 글자를 소리로 읽어 주는 프로그램이다. 눈으로 보지 않고 소리와 키보드만으로 결제까지 갈 수 있는지가 접근성 시험의 대표 항목이다.

이 표에서 지금 가져갈 것은 딱 하나다. 오른쪽 칸의 사례들은 기능 테스트를 아무리 꼼꼼히 해도 하나도 안 걸린다. 기능 테스트는 "혼자서, 평상시 조건에서, 최신 크롬으로, 본인 계정으로" 확인하기 때문이다.

기능이 통과해도 비기능이 무너지면 실제로 무슨 일이 일어나는가

"기능은 되는데 느리다"는 말은 추상적으로 들린다. 구체적인 결과로 바꿔보면 왜 이게 별도 범주여야 하는지가 분명해진다.

  • 사용자가 조용히 떠난다. 결제 버튼을 눌렀는데 8초 동안 아무 반응이 없으면 사용자는 버튼을 다시 누르거나 창을 닫는다. 이 사람은 버그 리포트를 쓰지 않는다. 기능 결함은 CS로 들어오지만, 성능 문제는 이탈률 그래프에만 남는다. 그래서 더 늦게 발견된다.
  • 중복 요청이 기능 결함을 만든다. 느려서 두 번 누른 결제가 두 건으로 들어가면, 그때부터는 성능 문제가 아니라 중복 결제라는 기능 결함이 된다. 비기능 문제가 기능 문제로 번지는 전형적인 경로다.
  • SLA 위반은 계약과 돈의 문제가 된다. B2B 서비스는 "월 가용성 99.9%", "응답 99퍼센타일 2초 이내" 같은 수치를 계약서에 적는다. 이걸 넘기면 배상·감액 조항이 걸린다. 이때 QA에게 오는 질문은 "왜 이걸 테스트 안 했나요"다.
  • 보안 결함은 되돌릴 수 없다. 기능 버그는 고치면 끝이지만, 유출된 개인정보는 회수할 수 없다. 신고 의무와 과징금이 따라붙는다.
  • 뒤늦게 고치려면 구조를 바꿔야 한다. 성능 문제의 원인이 화면 코드가 아니라 데이터 구조나 아키텍처에 있는 경우가 많다. 레슨 1의 비용 곡선이 비기능 결함에서 특히 가파른 이유다.

그래서 실무에서 자주 쓰는 문장이 있다. "기능 테스트는 제품이 존재하는지를 확인하고, 비기능 테스트는 그 제품을 쓸 수 있는지를 확인한다."

확인 테스트 vs 회귀 테스트

여기서 축이 한 번 더 바뀐다. 기능/비기능이 "무엇을 보는가"였다면, 확인/회귀는 "왜 지금 이걸 다시 돌리는가" 다. 둘 다 결함을 수정한 뒤에 하는 활동이고, 이름이 비슷해서 실무에서 가장 자주 섞인다.

확인 테스트 (Confirmation / Re-testing)회귀 테스트 (Regression)
질문이 결함이 진짜 고쳐졌는가?이 수정이 다른 곳을 망가뜨리지 않았는가?
대상원래 실패했던 그 케이스수정과 관련 있을 수 있는 주변 기능
케이스 출처결함 리포트의 재현 절차 그대로기존 테스트 스위트에서 골라낸 것

스위트(suite) 는 테스트 케이스를 한 묶음으로 모아 둔 것이다. "회귀 스위트" 는 "바꿀 때마다 돌리는 묶음" 을 가리킨다. | 개수 | 보통 13개 | 보통 수십수백 개 | | 자동화 적합도 | 낮음 (일회성이 많음) | 매우 높음 (반복 실행) | | 놓치면 생기는 일 | 안 고쳐진 버그를 고쳐졌다고 착각 | 새 버그(회귀 결함)를 릴리즈에 포함 |

확인 테스트에는 규칙이 하나 있다. 결함 리포트에 적힌 재현 절차를 한 글자도 바꾸지 않고 그대로 실행해야 한다. 다른 계정, 다른 금액, 다른 순서로 해보고 "되네요"라고 하면 그건 확인 테스트가 아니다. 원래 실패했던 그 조건이 통과해야 비로소 "고쳐졌다"고 말할 수 있다. 레슨 2의 도달·감염·전파 세 조건을 떠올려보자 — 조건을 살짝만 바꿔도 결함에 도달조차 못 할 수 있다.

코드로 보는 확인과 회귀

말로만 하면 여전히 흐릿하다. 실제 수정 하나를 놓고 보자. "정액 쿠폰이 적용되지 않는다"는 결함을 개발자가 이렇게 고쳤다.

  function calculateDiscount(total, coupon) {
-   return total * coupon.rate
+   if (coupon.type === "FIXED") {
+     return coupon.amount
+   }
+   return total * coupon.rate
  }

확인 테스트는 이 함수가 원래 실패했던 그 입력에서 이제 맞는 값을 내는지 본다. 결함 리포트에 적힌 그대로 — 3,000원 정액 쿠폰, 총액 20,000원.

입력기대확인할 것
type: "FIXED", amount: 30003,000원 할인리포트의 그 케이스가 통과하는가

회귀 테스트는 다른 질문을 한다. 이 함수를 부르는 다른 곳들이 여전히 멀쩡한가. 바뀐 것은 이 함수 하나지만, 이 함수의 결과를 쓰는 코드는 여러 개다.

// A) 결제 화면 — 최종 결제 금액
finalPrice = total - calculateDiscount(total, coupon)
 
// B) 상품 목록 — "이 쿠폰 쓰면 얼마?" 미리보기 배지
badgeText = `${calculateDiscount(previewTotal, coupon)}원 할인`
 
// C) 정산 배치 — 매출에서 할인액을 빼서 리포트 생성
netRevenue = grossRevenue - sumOf(calculateDiscount(...))

이제 회귀 질문이 구체적으로 나온다.

  • 정액 쿠폰이 총액보다 클 때 — 5,000원 쿠폰에 3,000원 주문이면 A는 음수 결제가 되는가? (수정 전에는 rate 곱셈이라 절대 총액을 넘지 못했다. 수정이 새로운 가능성을 열었다.)
  • B의 배지는 calculateDiscount가 비율일 때와 정액일 때 같은 문구를 쓰는가? "10% 할인"이라고 표시하던 자리에 "3000원 할인"이 들어가면 문구가 깨지지 않는가?
  • C의 정산 금액이 A의 결제 금액과 여전히 일치하는가? 둘이 어긋나면 회계가 안 맞는다.
  • 기존 정률 쿠폰은 그대로 동작하는가? (type이 "PERCENT"가 아니라 비어 있는 옛날 데이터가 있다면 어느 갈래로 가는가?)

마지막 항목이 회귀 테스트의 전형이다. 고친 것이 아니라 안 고친 것을 확인한다. 정률 쿠폰은 아무도 건드리지 않았지만, 같은 함수 안에 새 if가 생겼으므로 다시 확인해야 한다.

회귀 범위를 어떻게 좁히는가 — 영향 분석의 감각

여기서 실무의 진짜 난제가 나온다. 회귀 테스트를 전부 돌리면 안전하지만 느리고, 안 돌리면 빠르지만 사고가 난다. 그래서 필요한 것이 영향 분석(Impact Analysis) — "이 변경이 어디까지 번질 수 있는가"를 좁히는 작업이다.

거창한 도구 없이도 쓸 수 있는 휴리스틱이 있다. 아래 순서대로 물어보면 대부분의 현실적인 회귀 범위가 나온다.

단계질문어떻게 알아내는가
1무엇이 바뀌었나?PR의 변경 파일 목록을 본다 (모듈 9의 diff 읽기)
2그 파일을 누가 부르는가?저장소에서 함수명·파일명을 전체 검색한다
3그 호출자를 또 누가 부르는가?한 단계만 더 따라간다. 보통 2단계면 충분하다
4같은 데이터를 읽는 다른 기능은?같은 DB 테이블·같은 API를 쓰는 화면들
5과거에 여기서 터진 적 있나?결함 이력에서 같은 모듈 검색

2번이 가장 강력하면서 가장 안 쓰이는 방법이다. 코드 저장소에서 calculateDiscount를 검색하면 그 함수를 쓰는 파일이 전부 나온다. 개발자에게 "이거 어디서 써요?"라고 묻기 전에 30초면 스스로 알 수 있다. 개발자 도구를 쓸 줄 알면 여기에 하나 더 붙는다 — Network 탭에서 어떤 API가 그 값을 실어 나르는지 보면 화면 쪽 영향 범위도 잡힌다.

여기에 위험도 가중치를 얹는다. 영향 범위 안에 있더라도 전부 같은 무게가 아니다.

  • 돈이 오가는 경로(결제·정산·환불)는 영향 가능성이 낮아도 넣는다
  • 되돌릴 수 없는 동작(발송된 알림, 확정된 주문)도 넣는다
  • 최근 자주 깨진 영역은 확률이 실제로 높다
  • 반대로 사용률이 낮고 되돌리기 쉬운 화면은 이번엔 뺄 수 있다

이 판단은 모듈 2의 요구사항 변경 영향 분석, 모듈 4의 리스크 기반 테스트와 같은 근육이다. 그리고 회귀 스위트를 자동화해두면 이 고민의 상당 부분이 사라진다 — 1번부터 5번까지 따지는 대신 그냥 다 돌리면 되기 때문이다. 이게 모듈 11(자동화 전략)과 모듈 14(CI/CD)에서 회귀 테스트를 자동화 1순위로 꼽는 이유다.

사례 연구 — 30분 핫픽스가 이틀 뒤에 청구서로 돌아오다

앞의 조각들을 하나의 흐름으로 이어보자. 실제로 흔한 순서다.

화요일 14:00 — 제보. CS에 "정액 쿠폰이 적용 안 된다"는 문의가 20건 쌓였다. 매출에 직접 영향이 있으니 핫픽스로 결정된다.

14:30 — 수정. 개발자가 위의 diff대로 calculateDiscount에 if (coupon.type === "FIXED") 갈래를 추가한다. 세 줄짜리 변경이다.

15:00 — 확인 테스트. QA가 리포트의 재현 절차대로 3,000원 쿠폰을 20,000원 주문에 적용한다. 17,000원. 통과. 리포트에 "수정 확인 완료"를 남긴다.

15:10 — 생략된 판단. "세 줄 바꿨는데 뭐가 문제겠어요"라는 말이 나온다. 회귀 테스트는 다음 정기 릴리즈에 몰아서 하기로 하고 배포한다. 여기까지 40분. 팀은 이걸 성공적인 대응이라고 기억한다.

목요일 09:00 — 이상 신호. 정산 담당자가 "어제 매출 리포트의 할인 합계가 결제 합계와 12만원 안 맞는다"고 슬랙에 올린다. 아무도 결제 버그라고 생각하지 않는다. 정산 시스템 문제로 보였기 때문이다.

목요일 11:00 — 두 번째 신호. 고객이 "0원 결제가 됐는데 상품이 왔다"고 문의한다. 5,000원 정액 쿠폰을 3,000원짜리 소액 주문에 쓴 것이다. 수정 전에는 비율 곱셈이라 할인액이 절대 총액을 넘을 수 없었다. 정액 갈래가 그 보호막을 없앴다.

목요일 14:00 — 원인 확정. 화요일의 세 줄이 원인으로 밝혀진다. 그동안 이틀치 주문이 쌓였다. 이제 할 일은 코드 수정 하나가 아니다.

  • 이틀간 잘못 결제된 주문을 찾아내서 개별 보정
  • 정산 리포트 재생성
  • 영향받은 고객에게 안내
  • 원인 설명과 재발 방지책 보고

총 비용: 화요일에 회귀 테스트로 15분 쓰지 않아 목요일에 이틀 + 여러 팀의 시간을 썼다. 레슨 1의 결함 발견 시점별 비용 곡선이 정확히 이 모양이다. 그리고 이 사고는 확인 테스트를 안 해서가 아니라 확인 테스트만 해서 생겼다.

한 가지 더 짚을 것이 있다. QA가 15:10에 던졌어야 할 질문은 "회귀 테스트 해도 되나요?"가 아니다. 그건 시간을 달라는 요청으로 들려서 거절되기 쉽다. 이렇게 물어야 한다 — "이 함수를 쓰는 데가 결제 말고 두 군데 더 있는데, 정액이면 할인액이 총액을 넘을 수도 있습니다. 15분이면 이 세 가지는 확인됩니다." 범위와 시간을 함께 제시하면 협상이 가능해진다.

회귀 테스트 케이스는 어디서 오는가

회귀 테스트를 하라고 하면 "그럼 케이스를 새로 만들어야 하나?"라고 생각하기 쉽다. 아니다. 회귀 테스트 케이스는 이미 있는 것 중에서 고른다. 주된 출처는 셋이다.

  1. 기존 기능 테스트 케이스 — 예전에 만들어 통과시킨 것들
  2. 과거 결함에서 나온 케이스 — 한 번 터진 곳은 또 터진다. 결함을 고칠 때마다 그 케이스를 회귀 스위트에 넣는 습관이 가장 값싼 보험이다
  3. 핵심 흐름(Critical Path) — 로그인, 검색, 장바구니, 결제처럼 깨지면 서비스가 멈추는 경로. 변경 내용과 무관하게 항상 포함한다

그리고 회귀 스위트는 계속 커지기만 하면 결국 아무도 안 돌린다. 주기적으로 덜어내야 한다. 없어진 기능의 케이스, 몇 년째 한 번도 실패한 적 없으면서 실행에 오래 걸리는 케이스는 후보다. 테스트 스위트도 유지보수 대상이라는 감각은 모듈 7(테스트 문서·프로세스 개선)에서 이어진다.

스모크 테스트는 어디에 들어가는가

현장에서 자주 듣는 두 단어를 여기 끼워두면 지도가 완성된다.

이름언제무엇을
스모크(Smoke)새 빌드를 받자마자아예 테스트를 시작할 수 있는 상태인지. 로그인·주요 화면 진입 정도. 실패하면 즉시 반려
새니티(Sanity)작은 수정 뒤그 기능 주변만 빠르게. 좁고 깊은 회귀의 축소판
회귀(Regression)릴리즈 전영향 범위 + 핵심 흐름 전반

스모크와 새니티는 별개의 유형이라기보다 회귀 테스트를 시간 예산에 맞춰 잘라낸 크기들이라고 이해하면 된다. 팀마다 정의가 조금씩 다르니, 새 팀에 가면 "여기서 스모크는 뭘 도는 걸 말해요?"라고 한 번 물어보는 편이 낫다.

실무에서 왜 필요한가

"고쳤어요"와 "괜찮아요"는 다른 말이다. 개발자가 "고쳤어요"라고 할 때 그건 확인 테스트의 답이다. 릴리즈해도 되느냐는 질문의 답은 회귀 테스트에서만 나온다. 이 둘을 구분해서 말할 수 있는 것만으로 QA의 보고가 달라진다 — "수정은 확인했고, 영향 범위 세 곳 중 두 곳까지 봤습니다. 정산 쪽은 아직입니다"는 문장은 팀이 의사결정할 수 있는 정보다. "테스트 끝났어요"는 아니다.

핫픽스는 리스크가 가장 높은 배포다. 급하다는 이유로 절차가 줄고, 코드 리뷰가 얕아지고, 회귀가 생략된다. 정작 급한 상황일수록 사람은 더 실수한다. 위 사례처럼 "버그 하나 고칠 때마다 버그 하나가 새로 생긴다"는 평판은 팀의 배포 속도를 오히려 장기적으로 떨어뜨린다. 핫픽스일수록 범위를 좁히되 0으로 만들지 않는 것 — 이게 실무 QA의 판단력이다.

반대 방향의 실패도 흔하다. 매번 전체 회귀를 고집하면 릴리즈 주기가 늘어지고, 결국 팀이 QA를 우회하기 시작한다. "이번 건은 급해서 그냥 나갑니다"가 반복되면 프로세스 자체가 무력해진다. 회귀 범위를 근거를 대고 좁힐 수 있는 사람이 신뢰를 얻는다. 근거는 감이 아니라 영향 분석에서 나온다.

비기능을 나중으로 미루면 구조를 다시 짜야 한다. "일단 되게 만들고 성능은 나중에"는 거의 항상 비싸게 끝난다. 성능·보안의 원인은 화면이 아니라 데이터 구조와 아키텍처에 있는 경우가 많고, 그때는 이미 그 위에 다른 기능들이 얹혀 있다. QA가 기획 단계에서 할 수 있는 가장 값싼 기여는 "이 요구사항의 합격선은 숫자로 몇인가요?" 를 묻는 것이다 — 응답 시간, 동시 사용자 수, 지원 브라우저 범위. 답이 없으면 그건 아직 테스트 가능한 요구사항이 아니다(모듈 2에서 다룬다).

유형 구분은 회의에서 바로 쓰인다. "결제 테스트 했어요?"라는 질문에 유형 어휘가 있으면 정확히 답할 수 있다. "기능은 시스템 레벨까지 다 봤고, 부하는 아직 안 봤습니다. 쿠폰 수정 건 확인 테스트는 끝났고 회귀는 결제·정산까지 했습니다." 이 한 문장이 QA의 커버리지를 팀에 그대로 전달한다.

실습 과제

과제 1 — 유형 분류하기 (10분)

다음 각 활동이 기능/비기능/확인/회귀 중 무엇에 해당하는지 적는다. 둘 이상에 해당하는 것도 있다.

  1. 로그인 API에 초당 500 요청을 보내 응답 시간을 측정한다.
  2. "장바구니 수량 변경" 버그를 고친 뒤, 리포트의 재현 절차 그대로 다시 실행한다.
  3. 검색 필터를 새로 추가한 뒤, 기존 검색 정렬이 여전히 잘 되는지 돌려본다.
  4. 회원가입 폼에 이메일 형식이 아닌 값을 넣었을 때 거부되는지 확인한다.
  5. 결제 모듈을 수정한 뒤, 동시 결제 200건에서 여전히 3초 안에 끝나는지 측정한다.
해설 보기
  1. 비기능(성능·부하). 응답이 오느냐가 아니라 얼마나 빨리 오느냐를 본다.
  2. 확인 테스트. "리포트의 재현 절차 그대로"가 핵심 단서다.
  3. 회귀 테스트. 정렬 기능은 아무도 안 건드렸는데 다시 돈다 — 전형적인 회귀다. 그리고 확인하는 내용 자체는 기능이다.
  4. 기능. 입력 유효성 검사는 기능 요구사항이다.
  5. 비기능 + 회귀. 두 축이 겹치는 칸이다. 성능이라는 유형을, 수정 이후라는 맥락에서 돌리고 있다. "회귀는 기능만"이 아니라는 것이 이 문항의 핵심이다.

3번과 5번을 맞혔다면 "유형과 맥락이 서로 다른 축"이라는 이 레슨의 뼈대를 잡은 것이다.

과제 2 — 영향 범위 찾아보기 (15분)

"장바구니 상품 수량이 재고를 넘으면 담기 실패" 로직을 수정했다고 하자. 앞의 5단계 휴리스틱을 순서대로 적용해, 회귀 테스트에 넣을 주변 기능 3가지와 각각에서 확인할 내용을 한 줄씩 적는다.

해설 보기

예시 답이다. 정답이 하나는 아니지만, "왜 이걸 골랐는지"가 설명되면 성공이다.

주변 기능왜 영향 범위인가회귀로 확인할 것
결제결제 직전에 재고를 다시 검사한다담을 땐 통과했는데 결제 순간 재고가 0이 되면 어떻게 되는가
재고 차감·복원같은 재고 값을 읽고 쓴다담기 실패 시 재고가 잘못 차감된 채 남지 않는가
품절 알림·재입고 알림재고 수량 변화를 구독한다재고가 0이 아닌데 품절 알림이 나가지 않는가

여기에 하나 더 얹으면 좋다 — 동시성이다. 마지막 하나 남은 재고를 두 사람이 동시에 담으면? 이건 기능 테스트로는 잘 안 잡히고 부하 테스트에서 드러난다. 비기능 축이 회귀 범위에 들어오는 지점이다.

과제 3 — 확인과 회귀를 나눠 쓰기 (10분)

아래 수정이 있었다고 하자.

  function canUseCoupon(user, coupon) {
-   return user.isMember
+   return user.isMember && !coupon.isExpired
  }

① 확인 테스트로 무엇을 실행할지, ② 회귀 테스트로 무엇을 실행할지 각각 두 개씩 적는다.

해설 보기

확인 테스트 — 원래 결함이 "만료된 쿠폰이 쓰였다"였을 것이다.

  • 만료된 쿠폰을 적용해서 이제 거부되는가 (리포트의 그 쿠폰 그대로)
  • 만료 처리에 맞는 안내 문구가 뜨는가

회귀 테스트 — 조건이 하나 늘었으므로 기존에 통과하던 경우가 여전히 통과하는지를 본다.

  • 유효한 쿠폰 + 회원 → 여전히 사용 가능한가 (가장 중요한 회귀)
  • 비회원 → 여전히 거부되는가
  • 오늘이 만료일 당일인 쿠폰은? — isExpired의 경계다. 자정 기준인가, 만료일 포함인가 (모듈 3의 경계값 분석)

세 번째가 보였다면 아주 좋다. 수정이 새 경계를 만들었으므로 그 경계 자체가 새 기능 테스트 대상이기도 하다. 확인·회귀·신규 기능 테스트가 한 수정 안에 다 들어있는 전형적인 모습이다.

과제 4 — 비기능 합격선을 숫자로 바꾸기 (10분)

아래 요구사항은 그대로는 테스트할 수 없다. 각각을 판정 가능한 문장으로 고쳐 쓴다.

  1. "검색이 빨라야 한다"
  2. "많은 사용자가 동시에 써도 괜찮아야 한다"
  3. "보안이 안전해야 한다"
  4. "쓰기 편해야 한다"
해설 보기
  1. "검색어 입력 후 결과 표시까지 95퍼센타일 1.5초 이내(상품 10만 건 기준)"
  2. "동시 사용자 1,000명에서 오류율 0.1% 미만, 평균 응답 2초 이내"
  3. 이건 한 문장으로 안 된다. 쪼개야 한다 — "타인의 주문번호로 주문 상세에 접근 시 403을 반환한다", "비밀번호는 평문으로 저장·전송되지 않는다"처럼 검증 가능한 항목들로.
  4. "처음 사용하는 사용자 5명 중 4명이 도움말 없이 3분 안에 주문 취소를 완료한다"

공통점은 숫자와 조건이다. 그리고 4번처럼 사용성도 측정 가능한 형태로 쓸 수 있다. "측정할 수 없으면 테스트할 수 없다"가 비기능 요구사항의 제1원칙이다. 회의에서 1~4번 같은 문장을 만나면 QA가 던질 질문은 하나다 — "그거 몇 초/몇 명/몇 퍼센트를 말씀하시는 건가요?"

과제 5 — 우리 팀 회귀 스위트 점검하기 (선택, 15분)

지금 소속(또는 최근 프로젝트)의 회귀 테스트 목록을 열어본다. 없다면 "릴리즈 전에 항상 확인하는 것"을 떠올려 적어본다. 그리고 세 가지를 세어본다.

  • 핵심 흐름(로그인·결제 등)이 다 들어 있는가
  • 과거 결함에서 나온 케이스가 몇 개나 되는가 — 0에 가깝다면 가장 값싼 개선 기회가 거기 있다
  • 비기능 항목이 하나라도 있는가 — 대부분의 팀에서 이 답은 "없다"이다

자가 체크리스트

  • 테스트 레벨(어느 범위)과 테스트 유형(무엇을)이 서로 다른 축임을 설명할 수 있다
  • 기능 테스트와 비기능 테스트를 "무엇을 하는가 vs 얼마나 잘 하는가"로 구분할 수 있다
  • 성능·부하·보안·사용성·신뢰성이 각각 어떤 질문인지 한 줄로 말할 수 있다
  • 비기능 요구사항은 숫자 기준이 없으면 판정할 수 없다는 것을 설명할 수 있다
  • 기능이 통과해도 비기능이 실패했을 때 실제로 벌어지는 일을 예로 들 수 있다
  • 확인 테스트와 회귀 테스트의 목적 차이를 설명할 수 있다
  • 확인 테스트는 리포트의 재현 절차를 그대로 실행해야 하는 이유를 안다
  • 코드 변경 하나를 보고 확인 테스트 케이스와 회귀 테스트 케이스를 나눠 적을 수 있다
  • 영향 분석 휴리스틱(무엇이 바뀌었나 → 누가 부르나 → 같은 데이터를 쓰나)을 적용할 수 있다
  • 회귀 범위를 좁힐 때 위험도(돈·되돌릴 수 없음·과거 결함)를 가중치로 쓸 수 있다
  • 회귀 테스트 케이스가 어디서 오는지 세 가지 출처를 말할 수 있다
  • 확인 테스트만 하고 회귀를 생략했을 때 벌어지는 일을 사례로 설명할 수 있다

흔한 실수

  • 확인 테스트를 자기 방식대로 다시 해본다. 다른 계정, 다른 금액, 다른 순서로 해보고 "되네요"라고 하면 확인 테스트가 아니다. 조건이 바뀌면 결함에 도달조차 못 할 수 있다(레슨 2). 재현 절차 그대로 실행하는 것이 규칙이다.
  • 회귀 테스트를 "그냥 다시 테스트하는 것"으로 뭉뚱그린다. 회귀 테스트는 특정 변경의 영향을 좁혀서 보는 것이지 무작정 전체 재실행이 아니다. 전체 재실행은 회귀 테스트의 한 형태일 뿐이고, 대부분의 팀에서는 시간이 안 나온다.
  • 변경 줄 수로 위험을 판단한다. "세 줄밖에 안 바꿨는데요"가 가장 위험한 문장이다. 위험은 줄 수가 아니라 그 코드를 몇 군데서 쓰는가와 어떤 가능성을 새로 열었는가에서 나온다. 위 사례의 세 줄이 정확히 그랬다.
  • 회귀 테스트를 "기능 테스트 다시 돌리기"로만 생각한다. 성능이 갑자기 느려지는 것도 회귀다. 응답 시간이 0.5초에서 4초가 됐다면 기능은 다 통과해도 회귀 결함이다.
  • 비기능 요구사항을 "나중에 여유 있으면"으로 미룬다. 성능·보안 문제는 기능이 다 완성된 뒤에 손대려면 구조를 바꿔야 할 수도 있어 훨씬 비싸진다.
  • 비기능 문제를 감상으로 보고한다. "좀 느린 것 같아요"는 고칠 수 없는 리포트다. "상품 1만 건일 때 검색 응답 8.2초(기준 2초), 1천 건일 때는 0.9초"라고 쓰면 원인 범위까지 좁혀준다.
  • 확인 테스트만 하고 끝낸다. "그 버그, 고쳤어요?"에 "네, 확인했어요"라고 답할 때 회귀를 빼먹었다면 정확히는 "그 버그는 고쳐졌는지 확인했지만 다른 곳은 안 봤다"는 뜻이다. 그 차이를 말로 구분해서 보고하는 것이 QA의 기본기다.
  • 핫픽스라서 회귀를 0으로 만든다. 급할수록 범위를 좁히되 없애지는 않는다. "15분이면 이 세 가지는 확인됩니다"처럼 시간과 범위를 함께 제시하면 대개 받아들여진다.
  • 회귀 스위트를 쌓기만 하고 덜어내지 않는다. 실행에 6시간 걸리는 스위트는 결국 아무도 안 돌린다. 없어진 기능의 케이스는 지우고, 오래 걸리면서 한 번도 실패한 적 없는 케이스는 실행 주기를 늘린다.

참고 자료

낯선 말 풀이

이 레슨에 나온 약어입니다. 본문에서도 처음 나올 때 점선으로 표시해 두었습니다 (제목과 링크 글자는 그대로 둡니다).

QA — 품질보증
만든 것이 쓸 만한지 확인하고, 애초에 덜 망가지게 만드는 방법을 정하는 일. "테스트"는 그 일의 일부다.
ISO/IEC — 국제표준화기구·국제전기기술위원회 공동 표준
두 국제 단체가 함께 낸 표준이라는 표시. 뒤에 붙는 숫자가 문서 번호다.
URL — 인터넷 주소
웹에서 무언가의 위치를 가리키는 주소 한 줄.
OS — 운영체제
기기를 돌리는 바탕 프로그램 — 윈도우, 맥, 안드로이드 같은 것.
CS — 고객 지원 · 칩 선택 신호
이 커리큘럼에서 두 가지로 쓰인다. ① 고객 문의와 불만을 직접 받는 조직 ② 여러 부품이 한 선을 나눠 쓸 때 "지금은 네 차례" 라고 하나를 고르는 신호. 앞뒤에 문의·고객이 있으면 ①, 통신·배선 이야기면 ②다.
SLA — 서비스 수준 협약
"이 정도 품질은 보장한다"를 고객과 글로 약속한 것. 못 지키면 보상 조항이 따른다.
PR — 풀 리퀘스트
"내가 고친 코드를 본체에 합쳐 달라"고 올리는 요청. 합치기 전에 사람들이 보고 의견을 단다.
DB — 데이터베이스
데이터를 넣어 두고 꺼내 쓰는 저장소. 보통 표 여러 개가 서로 연결된 형태다.
API — 응용 프로그램 인터페이스
프로그램끼리 주고받는 창구. 사람이 화면 버튼을 누르는 대신, 프로그램이 정해진 주소로 요청을 보내 답을 받는다.
CI/CD — 통합·배포 자동화
합치고 시험하고 배포하는 과정을 자동으로 이어 둔 흐름 전체.
ISTQB — 국제 소프트웨어 테스팅 자격 위원회
테스터 자격 시험을 만들고 용어를 정리하는 국제 단체.

용어집 전체 보기