개념
유지보수 대상이 바뀌는 지점
모듈 3(레슨 11)에서 MBT 의 작동 원리를 봤다. 모델을 그래프로 만들고 도구가 순회해 경로를 뽑는다는 것, 그리고 그 대가로 빠뜨림이 모델 한 곳으로 모인다 는 것까지였다.
이 모듈은 그 "모델 한 곳" 을 운영하는 법을 다룬다. MBT 도입은 흔히 "케이스를 자동으로 만들어 준다" 로 요약되지만 체감되는 변화는 다른 쪽이다.
| MBT 이전 | MBT 이후 | |
|---|---|---|
| 정본(single source of truth) | 테스트 케이스 문서 | 모델 파일 |
| 요구사항이 바뀌면 고치는 것 | 영향받는 케이스를 찾아 하나씩 | 모델의 정점·간선 몇 개 |
| 리뷰 대상 | 케이스 목록 | 모델, 그리고 생성 기준 |
| 품질이 무너지는 경로 | 케이스가 서서히 낡는다 | 모델이 틀리면 전부 틀린다 |
마지막 줄이 이 레슨의 존재 이유다. 케이스 문서는 100개 중 3개가 낡으면 3개만 낡는다. 모델은 한 군데가 틀리면 그 모델에서 생성된 케이스 전부가 같은 방향으로 틀리고, 그러고도 커버리지 리포트에는 100% 가 찍힌다. 그래서 MBT 를 쓰는 팀의 핵심 활동은 케이스 작성이 아니라 모델 리뷰 다. 이 레슨은 두 질문에 답한다 — 어떤 표기법으로 그릴지, 그리고 그린 모델이 쓸 만한지 어떻게 판정할지 다.
표기법 (1) UML 상태기계 — 시스템이 "어떤 상태에 있는가" 가 본질일 때
모듈 3(레슨 3)의 상태 전이표를 표준으로 정식화한 것이 UML 상태기계(State Machine Diagram)다. 구성 요소는 네 가지다.
| 요소 | MBT 에서의 역할 |
|---|---|
| 상태(state) | 그래프의 정점. 여기서 검증(assertion) 을 수행 |
| 전이(transition) | 그래프의 간선. 여기서 동작(action) 을 수행 |
| 가드(guard) | 참일 때만 그 간선이 선택 가능 |
| 액션(action) | 모델 변수를 갱신해 이후 가드를 좌우 |
표준 표기는 전이 하나를 이렇게 적는다.
결제대기 --[ 결제승인 / amount > 0 / paidAt = now() ]--> 결제완료
└ 이벤트 └ 가드 └ 액션가드와 액션이 있다는 점이 단순 상태 전이표와 결정적으로 다르다. 가드 덕분에 같은 이벤트가 조건에 따라 다른 상태로 갈라지고, 액션 덕분에 모델이 자체 변수를 들고 다닌다. 재고 수량·시도 횟수·잔액처럼 상태 이름으로 표현하면 폭발 하는 값을 모델 변수로 빼내는 것이 MBT 모델링의 기본 기술이다.
폭발을 막는 장치가 둘 더 있다. 계층 상태(composite state) 는 로그인됨 안에
둘러보기·장바구니·결제중 을 품어 "로그인됨이면 어디서든 로그아웃 가능" 을
전이 하나로 적게 해 준다. 직교 영역(orthogonal region) 은 독립적인 두 축을
곱집합으로 펼치지 않아 상태 수를 2 x 2 = 4 에서 2 + 2 로 줄인다.
다만 도구가 계층·직교를 지원하는지 반드시 확인해야 한다. 많은 MBT 생성기는 평탄한(flat) 그래프만 받는다. 그 경우 계층 모델은 사람이 읽는 산출물로 두고 생성기용 모델은 평탄화한 별도 파일로 유지하게 되는데, 그 둘이 어긋나는 것이 새로운 유지보수 문제 가 된다.
표기법 (2) BPMN — "누가 무엇을 하는 절차인가" 가 본질일 때
BPMN(Business Process Model and Notation)은 비즈니스 프로세스 표기 표준이다. 상태기계와 결정적으로 다른 점은 상태가 아니라 활동(activity)과 흐름을 그린다 는 것, 그리고 수행 주체(레인)와 참여자 간 메시지가 1급 요소 라는 것이다.
| BPMN 요소 | 테스트 설계에서 읽히는 것 |
|---|---|
| 태스크(task) | 한 사람·시스템이 하는 한 단위 작업. 테스트 스텝의 후보 |
| 배타 게이트웨이(XOR) | 조건 분기. 분기별로 최소 한 경로씩 필요 |
| 병렬 게이트웨이(AND) | 동시 진행. 순서가 정해지지 않은 조합 이 생긴다 |
| 레인(lane)·풀(pool) | 수행 주체. 역할별 권한 테스트의 근거 |
| 메시지 흐름 | 시스템 경계를 넘는 호출. 인터페이스 테스트 지점 |
| 경계 이벤트(타이머·오류) | 타임아웃·예외 경로. 결함이 가장 많이 숨는 곳 |
전자결재·대출 심사·보험 청구·반품 처리처럼 여러 역할이 순서대로 개입하고 중간에 반송·보류·기한 초과가 끼어드는 업무가 BPMN 의 영역이다. 상태기계로 그리면 상태 이름이 업무 단계의 복제가 되고 "누가 하는가" 가 사라진다.
약한 곳도 있다. BPMN 자체는 "이 활동이 끝난 뒤 시스템이 어떤 상태인가" 를 말해 주지 않아 검증 지점을 사람이 붙여야 한다.
표기법 (3) 결정 표 — "조건 조합이 본질이고 순서는 없을 때"
모듈 3(레슨 3)의 결정 표는 가장 단순하면서 가장 과소평가된 모델이다. 상태도 흐름도 없고 조건의 조합과 그에 대한 결과만 있다.
조건1 회원 등급이 VIP 인가 Y Y N N
조건2 주문 금액이 5만원 이상인가 Y N Y N
---------------------------------------------
액션 무료배송 적용 O O O X
액션 적립률 5% 5% 2% 2%보험료 산정, 요금제 적용, 권한 판정, 할인 정책처럼 "지금까지 무슨 일이 있었는지" 와 무관하게 현재 입력만으로 결과가 결정되는 로직이 결정 표의 영역이다. 상태기계로 그리면 상태가 조건 조합 수만큼 생긴다.
세 표기법을 고르는 기준
| 질문 | 예 → 표기법 |
|---|---|
| 같은 입력인데 이전 이력에 따라 결과가 다른가? | UML 상태기계 |
| 여러 역할이 순서대로 개입하고 반송·기한이 있는가? | BPMN |
| 현재 입력 조합만으로 결과가 정해지는가? | 결정 표 |
| 금지된 전이를 명시해야 하는가? | 상태기계 + 부정 전이 |
현실의 시스템은 대개 셋을 계층으로 섞어 쓴다.
BPMN 반품 업무 전체 절차 (접수 → 회수 → 검수 → 환불)
└ 상태기계 반품 건 하나의 상태 (접수됨 → 회수중 → 검수중 → 환불완료 / 반송)
└ 결정 표 "환불 금액 계산" 한 전이의 가드와 액션 (등급 x 사유 x 경과일)상태기계는 전이·N-스위치 커버리지로 돌리고(레슨 2), 결정 표는 조합 기준으로 따로 돌린 뒤 가드 입력으로 공급한다. 한 모델에 전부 밀어넣지 않는 것이 모델 품질의 출발점이다.
모델 품질 — 테스트를 뽑기 전에 모델을 검사한다
아래 여섯 가지는 생성기를 돌리기 전에, 모델 파일만 보고 판정할 수 있다.
(1) 도달 불가 상태(unreachable state)
시작 상태에서 어떤 전이를 밟아도 닿을 수 없는 상태다. 그래프 탐색 한 번으로 찾는다. 원인은 둘 중 하나고 둘 다 보고할 거리다 — 진입 전이를 빠뜨린 모델 결함 이거나, 실제로 진입 경로가 없는 제품 쪽 죽은 상태 다. 방치하면 커버리지 분모가 채워지지 않아 100% 를 목표로 한 정지 조건이 끝나지 않는다(레슨 3).
(2) 데드엔드(dead end) / 싱크 상태
나가는 전이가 없는 상태다. 주문완료 처럼 의도된 종료 상태 인지, 결제실패
처럼 빠뜨린 복귀 전이 인지 구분해야 한다. 판정 기준은 하나다 — 실제 제품에서
사용자가 그 화면에 갇히는가. 갇히지 않는데 나가는 전이가 없으면 모델이 틀렸다.
의도되지 않은 데드엔드는 순회 생성기에 치명적이다. 무작위 순회가 거기 빠지면
경로가 그 자리에서 끊긴다.
(3) 비결정성(nondeterminism)
같은 상태에서 같은 이벤트로, 가드가 동시에 참이 되는 전이가 둘 이상 있는 경우다.
배송준비 --[ 취소요청 / 결제후 24시간 이내 ]--> 취소완료
배송준비 --[ 취소요청 / 출고지시 전 ]--------> 취소대기두 가드는 동시에 참이 될 수 있다. 결제 10분 뒤에 출고지시 전이면 어느 전이를 타는가? 모델은 답하지 않는다. 생성기는 임의로 하나를 고르고, 그 결과 테스트가 어떤 날은 통과하고 어떤 날은 실패한다 — 플래키 테스트의 원인이 코드가 아니라 모델에 있는 경우다. 판정은 기계적으로 가능하다. 같은 출발 상태·같은 이벤트를 가진 전이들을 묶어 가드들이 서로 배타적인지 확인하고, 배타적이지 않으면 우선순위를 명시하거나 가드를 쪼갠다.
배송준비 --[ 취소요청 / 출고지시전 && 경과 ≤ 24h ]--> 취소완료
배송준비 --[ 취소요청 / 출고지시전 && 경과 > 24h ]--> 취소대기(4) 가드의 중복과 누락
위 수정안이 보여 주는 두 성질에 이름을 붙인다. 결정 표의 완전성·무모순성 검사와 같은 개념이다.
| 성질 | 질문 | 위반하면 |
|---|---|---|
| 배타성(중복 없음) | 두 가드가 동시에 참이 될 수 있는가? | 비결정성 → 재현 불가 테스트 |
| 완전성(누락 없음) | 모든 입력 조합이 어떤 가드에도 걸리지 않을 수 있는가? | 침묵 실패 → 전이가 막혀 그 경로가 생성되지 않는다 |
누락이 더 위험하다. 중복은 테스트가 흔들려 눈에 띄지만, 누락은 그 전이가 조용히 선택되지 않아 커버리지 숫자만 조금 낮아진다. 그래서 모델 리뷰 양식에는 상태별로 가드 집합을 모아 "이 가드들의 논리합이 항상 참인가" 를 적는 칸 을 둔다.
(5) 추상화 수준의 일관성
한 모델 안에 사용자 관점 상태와 구현 관점 상태가 섞이면 생성된 경로를 실행 코드로 옮길 수 없다.
나쁜 모델: 장바구니 → 결제수단선택 → PG_API_호출중 → DB_트랜잭션_커밋 → 주문완료
좋은 모델: 장바구니 → 결제수단선택 → 결제진행중 → 주문완료PG_API_호출중·DB_트랜잭션_커밋 은 테스트가 관찰할 수도, 그 상태로 직접
전이시킬 수도 없는 내부 단계다. 모델에 넣으면 전이는 늘어나는데 검증할 것이
없는 간선 이 생긴다. 판정 질문은 하나다 — 이 상태를 테스트 코드가 관찰할
수 있는가, 이 전이를 테스트 코드가 일으킬 수 있는가.
반대 방향의 오류도 있다. 사용중 하나로 뭉치면 전이 커버리지 100% 가 아무것도
말해 주지 않는다. 적정 수준의 기준은 "상태가 바뀌면 사용자가 할 수 있는 일이
바뀐다" 다 — 할 수 있는 일이 같으면 같은 상태다.
(6) 부정 전이의 명시 여부
모듈 3(레슨 3)의 상태-이벤트 매트릭스에서 빈칸이 전체의 80% 였던 것을 떠올리자. 모델에 화살표가 없으면 도구는 그 조합을 시도하지 않는다. 금지 전이를 테스트하려면 "이 전이는 거부되어야 한다" 는 간선을 명시적으로 넣는다.
배송완료 --[ 주문취소 / 항상 ]--> 배송완료 (액션: 400 응답과 상태 불변을 검증)출발과 도착 상태가 같고 검증 내용이 "거부됨" 인 간선이다. 모델이 커지는 대신 빈칸의 존재가 모델 안에 기록되어, 리뷰에서 "이 조합은 왜 없나" 를 물을 수 있다.
나쁜 모델에서 나온 테스트는 많기만 하다
| 모델 결함 | 생성 결과 | 리포트에 보이는 모습 |
|---|---|---|
| 도달 불가 상태 | 그 영역 케이스 0개 | 커버리지 100% 가 영원히 안 나옴 |
| 데드엔드 | 경로가 짧게 끊김 | 케이스 수는 많은데 평균 길이가 짧음 |
| 비결정성 | 같은 설정에서 다른 경로 | 간헐적 실패. 코드를 들여다봐도 원인 없음 |
| 가드 누락 | 그 전이가 선택되지 않음 | 아무 증상 없음. 커버리지만 조금 낮음 |
| 과도하게 상세한 모델 | 케이스 수 폭발 | "케이스 4,000개" — 검증 없는 간선이 대다수 |
| 과도하게 뭉친 모델 | 케이스 소수 | 전이 커버리지 100%, 결함 검출 0 |
MBT 도입 6개월 차 팀이 가장 흔히 맞는 상황이 마지막 둘이다. 케이스 수는 수동 시절의 10배인데 발견 결함은 늘지 않는다. 원인은 생성기가 아니라 모델이다.
실무에서 왜 필요한가
MBT 도입 제안이 거절되는 전형적인 이유는 "모델을 믿을 수 없다" 다. 이때 "모델을 잘 그리겠습니다" 는 답이 되지 않는다. "모델을 여섯 항목으로 정적 검사하고 그 결과를 리뷰 기록으로 남깁니다" 가 답이다. 도달 불가 상태·데드엔드· 비결정성은 사람의 판단 없이 그래프 탐색으로 찾히므로 이 검사는 CI 에 넣을 수 있다 — 모델 파일이 바뀔 때마다 돌아가는 린트가 된다.
표기법 선택도 실질적인 이득을 준다. 요금 정책을 상태기계로 그리려다 상태가 수십 개로 불어나 포기하는 일, 반품 업무를 상태기계로 그려 "누가 승인하는가" 가 모델에서 사라지는 일이 반복된다. "이 로직은 상태가 본질인가, 절차가 본질인가, 조건 조합이 본질인가" 를 먼저 묻는 습관이 그 몇 주를 아낀다.
가드의 완전성을 따지다 보면 "경과 24시간의 시작점이 결제 시각인가 승인 시각인가" 같은 질문이 나온다. 그건 명세의 공백 이다(레슨 4의 워크숍 절).