실패 범위 재현과 이관
210분 안팎
학습 목표
로그인·권한·입력·통신 문제를 증거로 분리합니다.
개념
재현은 원인을 입증하는 실험의 출발점입니다
동아리 신청 화면에서 “확인할 수 없습니다”가 보였다는 문의를 받았습니다. 같은 문구라도 본인 내역 조회와 타인 승인 요청은 실패 조건이 다릅니다. 재현은 전제를 고정하고 한 행동의 결과를 비교하는 과정입니다. 모의 API는 각 조건의 응답을 읽는 연습을 돕지만 실제 장애의 원인을 밝히지는 않습니다. 담당자는 어떤 조건에서 같은 결과를 보았는지와 어느 조건은 아직 확인하지 않았는지를 함께 전달합니다. 재현 성공이라는 말만으로 운영 문제가 해결되었다고 쓰지 않습니다.
응답 계약을 먼저 읽습니다
mock_api.py의 call은 case 이름을 받아 status, code, requestId를 반환합니다. expired는 401과 SESSION_EXPIRED, denied는 403과 PERMISSION_DENIED입니다. invalid는 400과 INVALID_EVENT이고 timeout은 상태가 없는 TIMEOUT입니다. 이 조합은 실습에서 정의한 계약입니다. 코드 숫자만 보고 모든 401을 세션 만료로 해석하지 않습니다. 이번 분류 함수는 상태와 업무 코드가 함께 맞을 때만 정해진 분류를 반환합니다. 기대하지 않은 조합은 unknown으로 보존해 계약 확인을 요청합니다.
인증과 권한을 다른 질문으로 확인합니다
세션 만료에서는 로그인 주체를 다시 확인해야 합니다. 권한 거부에서는 로그인했더라도 본인 신청인지, 행사 운영자 역할인지, 담당 행사 범위인지 대조합니다. 유효 회원 U02가 U01 내역을 볼 수 없는 것은 앞 정책의 정상 방어와 맞을 수 있습니다. 권한을 임의로 확대해 오류 문구를 없애지 않습니다. 지원 담당이 역할 변경을 약속하기보다 본인 내역 경로를 안내하고 역할 기록이 기대와 다를 때 내부 담당자가 검토하도록 이관합니다. 권한 거부와 결함을 같은 말로 쓰지 않습니다.
입력 오류는 필드 계약과 비교합니다
INVALID_EVENT는 제공 계약에서 행사 입력이 유효하지 않다는 분류입니다. 사용자가 입력한 값과 허용 범위, 빈 값 여부, 화면에서 선택할 수 있는 값인지 확인합니다. 실습에서는 가명 code를 읽는 데 집중하며 임의 운영 데이터로 재현하지 않습니다. 잘못된 입력에 오류 응답을 준 것 자체는 결함이 아닐 수 있지만 사용자가 고칠 방법을 알 수 없다면 안내 개선의 대상입니다. 개발 이슈에는 입력 판정의 타당성과 화면 문구의 이해 가능성을 나누어 적습니다. 입력 오류에 재로그인을 권하는 것은 확인 조건과 맞지 않습니다.
시간 초과는 저장 실패의 증거가 아닙니다
timeout fixture는 응답을 받지 못한 상태를 뜻하며 서버 저장 결과를 포함하지 않습니다. 실제 제출에서는 응답을 못 받아도 처리되었을 가능성이 있습니다. 따라서 새 제출을 반복하라는 안내보다 본인 신청 내역 조회로 접수 여부를 확인하는 행동을 먼저 제안합니다. 조회도 실패하면 사용자 시각과 가능한 요청 번호를 가지고 내부 요청 기록을 대조합니다. requestId가 null이면 서버가 요청을 못 받았다고 결론 내리지 않습니다. 클라이언트가 번호를 전달받지 못했을 수도 있어 부재는 확인 범위의 한계입니다.
한 번에 한 조건을 바꿉니다
만료 세션의 본인 조회를 먼저 실행하고 같은 역할·조회 대상으로 세션만 유효하게 바꾸는 비교를 설계합니다. 브라우저와 계정과 입력을 동시에 바꾸면 어떤 차이가 결과를 바꾸었는지 알기 어렵습니다. 제공 call 함수는 고정 fixture이므로 success 사례는 정상 응답의 형식을 확인하는 별도 예입니다. 이를 실제 재로그인 전후 실험처럼 설명하지 않습니다. FAQ의 가상 재확인은 별도의 provided-support.json 카드로 다룹니다. 재현 도구가 보여 준 사실과 별도 확인 카드가 제공하는 사실을 섞지 않습니다.
로컬 출력의 열을 읽습니다
bash replay.sh의 한 줄은 case, status, code, category, requestId 순서입니다. NONE은 HTTP 상태나 요청 번호가 관측되지 않았다는 표시이며 0이라는 상태 코드를 뜻하지 않습니다. server의 503 UNAVAILABLE은 unknown으로 남깁니다. 이는 영향이 없다는 뜻이 아니라 제공 계약만으로 특정 근본 원인 분류를 확정하지 않았다는 뜻입니다. 표준 출력에는 가명 값만 있고 인증 헤더는 없습니다. 출력 열 순서가 달라지면 분류가 맞더라도 전달 문서에서 값이 뒤바뀔 수 있으므로 열 의미를 붙여 읽습니다.
검사 실패는 비교할 위치를 알려 줍니다
starter의 classify.py는 success와 나머지 unknown만 반환하므로 일부 사례가 실패합니다. python3 check.py에서 AssertionError가 나오면 subTest의 case와 실제 반환값, 기대 반환값을 비교합니다. 먼저 expired 하나를 구현해 확인하고 denied·invalid·timeout을 이어 작성합니다. mismatched_code 검사는 숫자만 맞아도 확정 분류하지 않는 경계를 확인합니다. ModuleNotFoundError는 실습 파일이 빠졌거나 실행 위치가 잘못되었는지 점검할 신호입니다. 네트워크 설치로 해결하기 전에 제공 파일 구성을 확인합니다.
이관 이슈는 다음 담당자의 실행 문서입니다
제목에는 행동과 조건과 실패 결과를 넣습니다. “오류 수정”보다 “유효 회원의 본인 조회에서 권한 거부가 관측됨”이 조사 범위를 보여 줍니다. 환경, 전제, 재현 단계, 기대, 실제, 증거 ID, 사실, 가설, 다음 확인을 순서대로 적습니다. 영향은 확인된 사용자와 행동 범위만 기록합니다. 모의 사례 세 건을 전체 사용자 장애라고 확대하지 않습니다. 로그는 필요한 요청 번호와 시간 범위로 내부 담당자가 찾게 하고 공개 문서에는 전체 내용을 붙이지 않습니다.
영향과 원인 확실성은 다른 축입니다
원인을 모른다고 영향이 작아지는 것은 아닙니다. 다수 사용자에게 접수 결과를 확인할 수 없는 현상이 관측되면 원인 미확인 상태로도 신속히 공유할 수 있습니다. 반대로 한 번의 권한 거부가 확인되었다고 전면 중단을 선언하지 않습니다. 확인된 범위, 시작 시각, 계속되는지 여부, 우회 가능성을 따로 적습니다. 이번 가상 문의에서 SUP03의 저장 여부는 미확인이고 SUP02는 안내 후 결과가 pending입니다. 서로 다른 미결 상태를 한 “미해결” 메모로 뭉개지 않으면 다음 확인이 구체적입니다.
이관의 완료 조건을 합의합니다
개발팀에 보냈다는 것과 사용자 문제가 해결되었다는 것은 다릅니다. 이관 문서에는 담당자와 다음 확인 시점, 확인할 결과를 넣습니다. 개발팀이 추가 로그를 확인하면 지원 담당은 사용자에게 내역이 보이는지 다시 묻습니다. 재현되지 않을 때에도 정상으로 종료하지 말고 시도한 조건, 횟수, 결과와 남은 차이를 기록합니다. 이번 미션은 SUP02·SUP03을 openCaseIds에 보존합니다. 앞 모듈의 I02·I03 보류 및 D01 미결은 문의가 추가되었다는 이유로 자동 승인하지 않습니다.
개발팀 전달 전에 동료가 읽습니다
동료가 제공 fixture와 응답을 대조하고 기대 결과가 접근 정책에 맞는지 확인합니다. 타인 조회에서 실제 거부를 기록하면서 기대를 허용으로 쓰면 앞 정책과 충돌합니다. 반대로 본인 조회 거부라면 역할·소유권 기록을 더 확인해야 합니다. 문서 검토는 이런 의미 차이를 찾는 과정입니다. 자동 검사가 통과해도 사실 문장에 추측이 섞였는지 사람이 읽습니다. 이관 뒤 추가 사실이 생기면 기존 기록을 덮어쓰지 않고 시점이 있는 후속 기록을 남겨 판단 변화의 이유를 추적합니다.
따라하기
정상과 실패 전제를 읽습니다
로컬 레슨 starter의 mock_api.py에서 expired·denied·invalid·timeout 응답을 읽습니다. denied는 타인 조회 거부의 정상 방어 가능성을 포함합니다. classify.py의 정상·미확인 기본 분류는 남겨 둡니다.
분류 함수를 구현하고 모의 요청을 재생합니다
classify.py에 상태와 코드 조합을 대조하는 분기를 작성합니다. 만료·권한·입력·응답 미수신을 분리하고 나머지는 unknown으로 반환합니다. 완성 후 패키지 루트에서 실행합니다. 열은 case status code category requestId 순서입니다. 이 출력은 solution을 직접 실행한 결과입니다.
bash replay.sh실행 결과
expired 401 SESSION_EXPIRED session-expired REQ01 denied 403 PERMISSION_DENIED permission-denied REQ02 invalid 400 INVALID_EVENT input-invalid REQ03 timeout NONE TIMEOUT network-unknown NONE success 200 OK success REQ04 server 503 UNAVAILABLE unknown REQ05 other 418 UNMAPPED unknown REQ06
경계 사례까지 검사합니다
python3 check.py를 실행합니다. starter에서는 분류 미구현 사례의 AssertionError가 나옵니다. expired부터 하나씩 고치고 mismatched_code도 unknown인지 확인합니다. 정상과 미확인 기본 사례를 유지한 채 테스트가 모두 OK인지 확인합니다.
이관 문서로 옮깁니다
미션의 SUP02·SUP03에 환경·순서·기대·실제·응답·증거를 채웁니다. SUP02 기대는 타인 접근 거부이고 SUP03 저장 여부는 미확인입니다. fact와 hypothesis를 나누고 owner와 nextCheck에 다음 조사 행동을 씁니다. openCaseIds에 두 문의를 남깁니다.
확인 문제
실습
classify.py를 수정해 만료는 session-expired, 권한은 permission-denied, 입력 오류는 input-invalid, 상태 없는 TIMEOUT은 network-unknown으로 반환합니다. 200 OK는 success이며 나머지 조합은 unknown입니다. mock_api.py와 check.py는 수정하지 않습니다. bash replay.sh로 결과 열을 읽고 python3 check.py로 전체 조합과 불일치 경계를 확인합니다.
실행 명령
python3 check.py
기대 결과
unittest 검사 OK; 상태/코드 조합 7개와 불일치 코드 경계 통과
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 사용자가 로그인이 안 된다고 할 때 확인할 순서를 설명해 주시면 됩니다.