상태 전이 (State Transition) 다이어그램과 테스트 설계

핵심 인사이트 (3줄 요약)

  1. 본질: 상태 전이(State Transition) 테스팅은 소프트웨어가 과거의 입력값(History)에 따라 현재의 **상태(State)**를 다르게 기억하고, 특정한 이벤트(Event)가 발생했을 때 어떻게 다음 상태로 변하는지(Transition)를 다이어그램으로 도식화하여 검증하는 블랙박스 테스트 기법이다.
  2. 가치: 동등 분할이나 결정 테이블이 '현재 입력값들의 정적인 조합'만 검사한다면, 상태 전이 기법은 **"비밀번호 3회 연속 틀렸을 때 계정 잠금"**처럼 시간의 흐름과 순서(Sequence)에 따라 동적으로 변하는 시스템의 복잡한 로직 결함을 100% 추적해 내는 유일한 시각적 무기다.
  3. 융합: 실무에서는 ATM 기기, 쇼핑몰 장바구니 결제 프로세스, 회원 가입 상태 머신(State Machine) 등 상태 변이(State Mutating)가 핵심인 도메인에 필수적으로 쓰이며, 시스템이 잘못된 입력(Invalid Event)을 받았을 때 뻗지 않고 이전 상태를 유지하는지(방어적 프로그래밍)를 역으로 검증하는 네거티브 테스트(Negative Test)와 강력하게 융합된다.

Ⅰ. 개요 및 필요성 (Context & Necessity)

  • 개념: 시스템은 상태(State), 이벤트(Event), 전이(Transition), 조치(Action) 4가지 요소로 움직이는 유한 상태 기계(Finite State Machine, FSM)로 모델링될 수 있다. 상태 전이 테스팅은 이 상태 머신이 설계된 다이어그램을 바탕으로, 가능한 모든 '상태 전이 경로'를 통과해 보는 테스트 스크립트를 도출하는 기법이다.

  • 필요성: 웹사이트에서 '결제하기' 버튼을 누른다. 장바구니에 물건이 없으면(State: Empty) 아무 일도 안 일어나고, 물건이 있으면(State: Filled) 결제창으로 넘어간다. 똑같이 '결제 버튼 클릭(Event)'을 했는데 시스템의 반응이 다르다. 즉, 소프트웨어는 과거의 상태를 기억하고 있기 때문이다. 만약 개발자가 상태 관리를 잘못해서 결제 완료 후(State: Paid)에 뒤로가기를 눌러 다시 결제 버튼을 누르는 걸 막지 않았다면? 이중 결제가 터진다. 이처럼 순서(Sequence)가 꼬였을 때 발생하는 최악의 버그를 막으려면 상태 간의 모든 이동 경로를 지도로 그려놓고 밟아보는 수밖에 없다.

  • 💡 비유: 지하철 개찰구(Turnstile)를 상상해 봅시다.

    • 상태 (State): 개찰구는 '잠김(Locked)' 또는 '열림(Unlocked)' 두 가지 상태만 있습니다.
    • 이벤트 (Event): '교통카드 찍기' 또는 '사람이 밀고 들어가기'라는 사건이 일어납니다.
    • 정상 전이 (Positive): '잠김' 상태에서 카드를 찍으면, 삑 소리가 나고 '열림' 상태로 바뀝니다.
    • 비정상 전이 (Negative): '잠김' 상태에서 카드를 안 찍고 몸으로 밀고 들어가려 하면, 삐빅! 경고음(Action)이 울리고 개찰구는 여전히 '잠김' 상태를 유지해야 합니다. 이 모든 경우의 수를 표로 만들어 확인하는 것이 상태 전이 테스트입니다.
  • 등장 배경 및 발전 과정:

    1. 순서 의존적 버그의 폭발: 초기 GUI 시스템과 웹이 발전하면서 사용자가 뒤로가기, 새로고침, 창 닫기를 마음대로 누름에 따라 데이터 꼬임 현상이 속출했다.
    2. UML 상태 다이어그램의 차용: 객체지향 설계(UML)의 Statechart Diagram이 테스트 케이스 설계 도구로 차용되며 블랙박스 기법으로 정립되었다.
    3. N-Switch 커버리지로의 진화: 단순히 A에서 B로 가는 것(0-Switch)을 넘어, "A→B→C로 갔다가 다시 A로 돌아오는" N번 연속된 상태 변화(N-Switch Coverage)까지 수학적으로 커버하는 고급 기법으로 고도화되었다.
  • 📢 섹션 요약 비유: 상태 전이 다이어그램은 롤플레잉 게임(RPG)에서 퀘스트 지도를 그리는 것과 같습니다. 유저가 "검을 먼저 줍고(상태 1), 마을 촌장에게 말을 걸어야만(이벤트)" 숨겨진 던전 문이 열리는데, 순서를 어기거나 엉뚱한 행동을 했을 때 게임이 튕기지 않고 안전하게 안내 메시지를 주는지 모든 갈림길을 걸어가 보는 꼼꼼한 모험입니다.


Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)

상태 전이 다이어그램 구성 요소와 작성법

쇼핑몰의 "주문(Order)" 상태 변화를 예시로 다이어그램을 그려보자.

  ┌───────────────────────────────────────────────────────────────┐
  │         상태 전이 다이어그램 (State Transition Diagram) 예시       │
  ├───────────────────────────────────────────────────────────────┤
  │                                                               │
  │   (Start) ── [이벤트: 결제 완료] ──▶ ( State: PAID )             │
  │                                       │                       │
  │     ┌──────── [이벤트: 배송 시작] ───────┘                       │
  │     │                                                         │
  │     ▼                                                         │
  │  ( State: SHIPPED ) ──── [이벤트: 고객 취소 요청] ────┐          │
  │     │                                             │           │
  │     │ [이벤트: 배송 완료]                              ▼           │
  │     │                                       ( State: REFUND ) │
  │     ▼                                             │           │
  │  ( State: DELIVERED )                             │           │
  │                                                   │           │
  │     └──────── [이벤트: 7일 경과] ───────────────┴─────────┐ │
  │                                                             │ │
  │                                                             ▼ │
  │                                                   ( State: DONE )
  │                                                               │
  │  ▶ 4가지 핵심 요소:                                              │
  │    1. 상태(State): PAID, SHIPPED, DELIVERED, REFUND, DONE     │
  │    2. 이벤트(Event): 결제 완료, 배송 시작, 배송 완료, 고객 취소 등      │
  │    3. 전이(Transition): 화살표 (상태가 바뀌는 흐름)                 │
  │    4. 액션(Action): 전이 시 발생하는 동작 (예: 환불 시 '결제 취소 API' 호출)│
  └───────────────────────────────────────────────────────────────┘

상태-이벤트 테이블 (State-Event Table) 도출 매커니즘

다이어그램을 그렸으면 이것을 **모든 전이의 유효(Valid)/무효(Invalid)를 촘촘히 검사하는 테이블(Table)**로 치환해야 한다. 여기서 진정한 테스트 케이스가 뽑혀 나온다.

현재 상태 (Current State)입력 이벤트 (Event)다음 상태 (Next State)기대 결과 (Action / Pass 여부)
1. PAID배송 시작SHIPPED배송 알림 톡 발송 (Valid)
2. PAID고객 취소 요청REFUND전액 환불 처리 (Valid)
3. SHIPPED배송 완료DELIVERED배송 완료 알림 톡 발송 (Valid)
4. SHIPPED고객 취소 요청SHIPPED (그대로)🚨 에러: "배송 중에는 취소할 수 없습니다" 팝업 노출 (Invalid 방어)
5. DELIVERED7일 경과DONE구매 확정 포인트 1% 지급 (Valid)

[테이블 해설] 다이어그램을 코드로 옮길 때 가장 치명적인 실수가 바로 표의 4번 케이스(Invalid)다. 개발자가 if (event == "고객 취소") { state = REFUND; } 라고만 대충 짜놓으면, 이미 택배가 출발했는데도(SHIPPED) 고객이 강제 취소 버튼을 연타하여 환불을 받아버리는 치명적 비즈니스 버그가 터진다. 이처럼 **"특정 상태에서는 절대 먹히면 안 되는 이벤트"**를 명확히 찾아서 상태 전이 무시(Ignore) 처리가 잘 되었는지 검증(네거티브 테스트)하는 것이 상태 전이 테이블의 존재 이유다.


Ⅲ. 실무 적용 및 기술사적 판단

실무 시나리오

  1. 시나리오 — 비밀번호 오류 횟수 잠금(Lock)의 경계값/상태 결합 버그: 로그인 시스템에서 비밀번호를 5번 틀리면 계정이 '잠금(Locked)' 상태로 바뀌고, 고객센터에 전화를 해야만 '활성(Active)' 상태로 풀리도록 요구사항이 내려왔다. 개발자는 카운트 로직을 짰지만, 해커가 4번 틀리고 1번 맞게 로그인한 뒤, 다시 1번 틀리자 갑자기 계정이 잠겨버리는 황당한 버그가 발생했다.

    • 판단: 전형적인 상태 변이 설계 오류(State Reset 누락)다.
    • 해결책: 상태 전이 다이어그램을 그려야 한다. '활성' 상태 내부에서 [이벤트: 비밀번호 틀림]이 발생하면 Error_Count++ 액션이 돌며 자기 자신으로 돌아오고, 이 카운트가 5가 되는 순간 [이벤트: 5회 오류 도달]이 트리거되어 '잠금' 상태로 넘어간다. 핵심은 [이벤트: 정상 로그인 성공]이 발생했을 때 반드시 Error_Count = 0으로 리셋(Action)해 주어야 한다는 흐름을 상태 머신에 명시해야 한다. 이 다이어그램을 보고 테스트 코드를 짰다면 Fail 4번 → Success 1번 → Fail 1번 콤보(N-Switch 테스트)를 통해 버그를 사전에 완벽히 막았을 것이다.
  2. 시나리오 — 마이크로서비스(MSA)의 분산 트랜잭션 롤백 상태 누락 (Saga Pattern): 주문 시스템(Order MSA)에서 PENDING 상태의 주문이 재고(Inventory) 부족으로 취소될 때, 개발자가 CANCELED 상태로만 넘기도록 코드를 짰다. 그러나 이미 결제망(Payment MSA)에서 돈이 빠져나간 뒤라, 돈은 환불되지 않은 채 주문만 사라진 고아(Orphan) 주문 사태가 터졌다.

    • 판단: 분산 시스템에서 상태 전이 도중 타 시스템 연동(Action) 실패에 대한 예외 상태(Compensation State) 설계가 누락된 것이다.
    • 해결책: 주문 상태 다이어그램에 분산 롤백 전용 상태를 추가해야 한다. PENDING에서 바로 CANCELED로 뛸 것이 아니라, 재고 부족 메시지를 받는 즉시 REFUNDING(환불 진행 중) 상태로 임시 전이한 후, 환불 외부 API가 성공했다는 [이벤트: 환불 완료 ACK]를 수신한 뒤에야 비로소 CANCELED라는 최종 종착지(End State)로 안착하게 설계해야 한다. 중간에 환불이 실패하면 REFUND_FAILED 상태에 머물러 관리자가 수동(Manual) 개입할 수 있도록 데드 레터(Dead Letter) 상태를 열어두는 것이 아키텍트의 의무다.

도입 체크리스트

  • 비즈니스적: 우리의 앱 화면에 "A 상태에서는 버튼이 회색(Disabled)이 되고, B 상태가 되어야만 버튼이 활성화(Enabled)된다"는 식의 동적 UI 규칙이 있는가? (상태 전이 테스트 없이는 이 UI 변경 버그를 100% 잡아낼 수 없다.)
  • 설계적 (N-Switch 커버리지): 단순히 A ─▶ B 로 가는 '0-Switch (All Transitions)' 커버리지만 맞췄는가? 사용자가 A ─▶ B ─▶ C ─▶ B ─▶ A 로 미친 듯이 뒤로 가기를 누르며 돌아다니는 복합 경로(N-Switch) 커버리지를 최소한 1단계 이상은 도출하여 테스트 케이스에 반영했는가?

Ⅳ. 기대효과 및 결론

정량/정성 기대효과

구분상태 무시 (직관적 단위 테스트)상태 전이 모델링 (State Machine)개선 효과
정량 (탐지율)순서 의존적 논리 버그 유출률 높음허용되지 않은 비정상(Invalid) 이벤트 타격상태/순서 꼬임으로 발생하는 치명적 버그 99% 차단
정량 (테스트 수)무한대의 클릭 순서(Monkey Test) 시도유효한 전이 경로만 계산된 최적화 케이스 추출완벽한 커버리지를 보장하면서도 케이스 개수 70% 절감
정성 (설계 개선)기획서에 "이럴 땐 어떻게 하죠?" 예외 누락다이어그램 그리는 순간 기획의 사각지대 발견방어적 프로그래밍(Defensive Programming) 문화 정착

소프트웨어 시스템에서 가장 잡기 힘들고 재현하기 어려운(Heisenbug) 버그는 대부분 '상태(State)와 순서(Sequence)의 꼬임'에서 발생한다. 기술사는 "우리 로직은 완벽해"라고 자부하는 개발자에게, "이미 배송된 물건을 취소 버튼을 누르면 어떤 일이 일어나는가?"라는 상태 역행(Backward Transition)의 맹점을 다이어그램으로 시각화하여 들이밀 수 있어야 한다. 닫힌 문은 흔들어보고, 열린 문은 닫아보는 이 치밀한 상태-이벤트 맵핑이야말로 가장 저렴하게 대형 사고를 막는 훌륭한 보험이다.


📌 관련 개념 맵 (Knowledge Graph)

개념 명칭관계 및 시너지 설명
블랙박스 테스트 (Black-box Testing)소스 코드를 보지 않고 기획서(다이어그램)만 보고 입력과 출력을 테스트하는 기법. 동등분할, 경계값, 결정테이블, 상태 전이가 그 4대 천왕이다.
FSM (유한 상태 기계)컴퓨터 과학에서 시스템을 "유한한 개수의 상태(State)"와 그 사이를 이동하는 조건으로 모델링하는 수학적 추상화 기법. 상태 전이 테스트의 근본 뼈대다.
네거티브 테스트 (Negative Test)사용자가 바보 짓(예: 잠긴 상태에서 열기 버튼 누름)을 했을 때 시스템이 죽지 않고 안전하게 에러를 뱉는지를 찌르는 공격적 방어 테스트다.
N-Switch Coverage상태 전이 테스트의 난이도 척도. 한 번만 이동(0-Switch)하는 건 쉽지만, 3번 이상 연속으로 이동(3-Switch)하는 경로까지 테스트하면 경우의 수가 폭발한다.
결정 테이블 (Decision Table)상태 전이는 '시간과 순서'의 흐름을 본다면, 결정 테이블은 그 찰나의 순간에 들어온 '입력 조건들의 동시 조합'을 검사하는 완벽한 짝꿍(상호 보완) 기법이다.

👶 어린이를 위한 3줄 비유 설명

  1. 신호등은 항상 [빨강 → 초록 → 노랑 → 빨강] 순서로만 바뀌어야(전이) 해요. 만약 초록불 다음에 갑자기 빨간불로 건너뛰어버리면(비정상 전이) 자동차들이 다 부딪히는 큰 사고가 나겠죠?
  2. 이 신호등 프로그램이 진짜로 올바른 순서대로만 불이 바뀌는지 검사하기 위해, 불이 바뀌는 모든 경우의 길(화살표)을 지도처럼 쫙 그려봤어요.
  3. 지도를 보고 "초록불일 때 빨간불 버튼(잘못된 이벤트)을 누르면 어떻게 될까?" 하고 일부러 엉뚱한 장난을 쳐보면서, 신호등이 고장 나지 않고 안전한 순서를 끝까지 유지하는지 꼼꼼하게 괴롭혀보는 걸 '상태 전이 테스트'라고 한답니다!