자동 회귀 실행 순서
110분 안팎
학습 목표
준비·API·UI·정리·증거 업로드를 연결합니다.
개념
단계 연결은 실패를 전달하는 계약입니다
API 가입 검사가 실패했는데 마지막 증거 복사가 성공하여 전체 빌드가 초록색이 되면 회귀 검사 결과를 믿을 수 없습니다. CI는 여러 명령을 호출하는 자동 실행 절차이며 각 명령의 결과가 최종 결과로 전달되어야 합니다. 동아리 서비스에서는 준비·API·UI·정리·공개 증거 준비라는 단계의 책임을 분리합니다.
준비 단계는 입력 파일과 의존성, 실행 조건을 점검합니다. API 단계는 응답과 저장 효과를 검사하고 UI 단계는 사용자 행동을 검사합니다. 앞 단계가 실패하면 뒤 일반 단계를 건너뛰어 불필요한 연쇄 오류를 줄입니다. 건너뛴 항목은 성공이 아니라 SKIPPED입니다. 릴리스 의견에는 그만큼 확인하지 않은 범위가 남습니다.
정리와 증거 준비는 성공 경로에만 붙이지 않습니다. 테스트가 실패해도 자신이 만든 데이터와 자원을 정리하고 실패 당시 관찰을 남겨야 합니다. 이번 레슨은 합성 명령으로 이 실행 정책을 먼저 확인합니다. 실제 계정·브라우저·Spring context의 해제는 미션에서 이어받은 검사 내부의 finally와 close가 맡습니다.
종료 코드를 먼저 보존합니다
종료 코드 0은 호출된 명령의 정상 종료를 나타내고 그 밖의 값은 실패로 다룹니다. 실제 의미는 명령 계약과 함께 읽습니다. 우리 합성 API 단계는 실패를 나타내기 위해 7을 반환합니다. 7이라는 숫자가 모든 도구에서 API 결함을 의미하는 것은 아닙니다. 단계 이름과 오류 내용이 있어야 조사 대상을 알 수 있습니다.
first 변수는 처음 나온 실패 코드를 보관합니다. 첫 실패가 7이고 정리가 8이면 최종 코드는 7을 유지하면서 두 실패를 각각 보고합니다. 마지막 명령의 성공값으로 first를 덮으면 원래 검사를 숨기게 됩니다. 보고서에서 정리 실패도 확인해야 잔여 데이터 위험을 다음 실행에 전달할 수 있습니다.
pipeline.py의 run_plan은 명령을 문자열 하나로 셸에 넘기지 않고 argv 목록으로 실행합니다. python3, stage.py, api, 7은 각각 인자입니다. 실습에서는 계획 파일을 신뢰한 작성자 입력으로 취급하며 외부 사용자 문자열을 실행 명령으로 받지 않습니다. 명령의 출력과 실행 정책을 분리하면 정책 검사를 독립적으로 작성할 수 있습니다.
성공과 실패의 순서를 표로 만듭니다
정상 입력에서는 prepare, api, ui, cleanup, publish가 모두 PASS입니다. API 실패 입력에서는 prepare가 PASS이고 api가 FAIL이며 ui만 SKIPPED입니다. cleanup과 publish는 항상 실행 대상입니다. 단계별 status와 exit를 함께 남기면 호출하지 않은 검사와 정상 종료한 검사를 명확히 구별할 수 있습니다.
준비 단계가 실패하면 API와 UI는 실행하지 않습니다. 이 상태에서 환경 문제를 제품 저장 오류로 분류하지 않습니다. publish는 기록할 자료가 부족하더라도 단계 호출을 시도할 수 있습니다. 자료가 없다는 사실을 보고서에 적고 이전 실행 파일을 이번 결과처럼 전달하지 않도록 실행 폴더와 자료 식별자를 확인합니다.
cleanup이 실패해도 publish는 시도합니다. 이미 수집한 실패 근거가 정리 오류 때문에 사라지지 않도록 두 마지막 단계를 독립적으로 실행합니다. 최종 종료 코드가 첫 실패를 유지한다는 정책과 이후 오류를 기록한다는 정책이 함께 필요합니다. 두 오류 중 하나만 남기면 제품 조사 또는 잔여 상태 조사를 놓칠 수 있습니다.
starter의 거짓 성공을 수정합니다
qa-ci-pipeline의 pipeline.py에는 first를 0으로 설정하는 TODO가 있습니다. 실패가 있을 때 first가 비어 있으면 이번 rc를 보관하고 이미 있으면 기존 값을 유지하도록 고칩니다. tests.py는 정상 실행, API 실패, 정리 추가 실패, 증거 준비 실패, 실행 파일 없음 다섯 가지 정책을 확인합니다. 기대값과 plan.json은 변경하지 않습니다.
bash check.sh는 정책 검사를 실행합니다. python3 pipeline.py plan.json은 별도의 합성 실행이며 API 실패를 의도해 종료 코드 7이 나옵니다. 이 명령이 0이어야 한다고 생각하여 plan.json의 API 숫자를 바꾸면 실습 목적을 잃습니다. 테스트 러너의 통과와 실패 주입 명령의 비정상 종료는 서로 다른 검증 대상입니다.
stage.py는 단계 이름을 출력하고 지정한 숫자로 끝나는 작은 모형입니다. cleanup이라는 문자열을 출력했다고 실제 회원 데이터를 삭제한 것은 아닙니다. 레슨은 호출 순서와 실패 전파를 확인하고 실제 데이터 정리는 이전 모듈의 격리 검사로 확인합니다. 각 검증의 관찰 범위를 말할 수 있어야 CI 결과를 과장하지 않습니다.
실패 로그를 읽는 위치를 정합니다
AssertionError에서 예상 최종 코드가 7인데 실제 0이면 first 보존 로직을 봅니다. 예상 status 목록과 실제 목록이 다르면 blocked와 always 조건을 봅니다. UI가 실행되지 않은 이유를 단계 목록에서 확인하면 마지막 화면 오류만 읽고 원인을 찾는 시간 낭비를 줄일 수 있습니다. 정책 오류와 검사 본문의 결함은 조사 위치가 다릅니다.
실행 파일이 없는 경우 subprocess가 OSError를 내며 제공 runner는 이를 127로 기록합니다. 이것은 우리 실행기의 정책입니다. 예외 메시지 전체를 공개 출력하지 않아 비밀 경로가 보고서에 섞이는 위험을 줄입니다. 자세한 환경 진단은 접근이 제한된 실행 로그와 명령 목록에서 확인하고 공개 보고에는 준비 실패 사실을 남깁니다.
셸에서 실패 뒤 정리하는 구조를 만들 때 set -e만 믿으면 정리 전에 종료될 수 있습니다. 제공 레슨은 Python runner가 결과를 모으도록 구성했습니다. 다른 구현을 선택하더라도 실패를 저장한 뒤 정리를 시도하고 원래 실패를 반환하는 같은 계약을 지켜야 합니다. 예외를 잡고 0으로 끝내는 방식은 증거 수집을 성공 판정으로 바꿉니다.
증거 업로드와 로컬 준비를 구별합니다
plan.json의 publish는 단계 호출 모형입니다. 미션의 publish는 reports/published에 허용한 JSON을 복사하는 로컬 staging이며 네트워크 업로드가 아닙니다. 실제 CI 서비스에 연결할 때에는 실행자가 이 폴더를 보관하는 별도 설정을 추가합니다. 여기서 실행하지 않은 업로드 서비스의 성공을 output에 적지 않습니다.
공개 후보에는 합성 재현 요약과 입력 해시만 둡니다. 앞 모듈의 private trace는 보관 폴더 전체를 복사하는 규칙에 포함하지 않습니다. UI PNG는 사람이 이미지의 마스킹을 확인한 뒤 별도로 공유합니다. 문자열 검색만으로 이미지 개인정보 부재를 보증할 수 없으므로 파이프라인의 자동 복사 범위를 좁힙니다.
산출물을 만들지 못한 단계도 실패로 남겨야 합니다. 테스트는 통과했으나 publish가 9로 실패하면 최종 결과가 실패여야 하며 검증 결과와 자료 보관 실패를 따로 설명합니다. 자료가 없는 채 통과 숫자만 전달하면 다음 조사자가 결과를 재현하기 어렵습니다. 이때 제품 결함이라고 단정하지 않고 보관 경로와 권한을 확인합니다.
미션에서 기존 검사를 연결합니다
미션의 ci/plan.json은 보존 검사, 이전 핵심 회귀, 새 triage, 실제 UI, 정리 확인, 공개 요약 준비를 연결합니다. core는 제공 프로젝트의 Java·API·Node 검사를 실행합니다. UI 단계는 JUnit이 임시 Spring 앱을 열고 Node 브라우저 검사를 호출하며 종료 시 닫습니다. 별도의 백그라운드 서버나 kill 명령을 만들지 않습니다.
자동 재시도는 이 실행 계획에 없습니다. 실패한 검사에 재시도를 붙여 초록색이 될 때까지 실행하면 첫 실패의 원인과 빈도를 잃습니다. 원인을 조사한 뒤 동일 입력의 재검증을 별도 실행으로 기록합니다. 불안정성의 반복 분석은 다음 모듈에서 다루며 여기서는 첫 결과가 전달되고 증거가 남는 실행 계약을 완성합니다.
완료 제출에는 다섯 정책 검사 결과와 합성 API 실패의 최종 종료 코드, 단계별 상태 목록을 남깁니다. 실패가 추가되어도 정리와 publish가 호출되는지 설명합니다. node:test의 일반 사용법은 더 읽기로 이어가고 이 레슨의 검토는 검사 수보다 실패 전파와 미실행 범위를 올바르게 전달하는 데 집중합니다.
따라하기
첫 실패와 뒤 성공을 비교합니다
합성 종료 코드 배열에서 처음 나온 실패가 7인지 직접 확인합니다.
codes=[0,7,0,0]
first=next((x for x in codes if x),0)
print('first failure:',first)
print('last command:',codes[-1])실행 결과
first failure: 7 last command: 0
runner의 실패 보존을 수정합니다
qa-ci-pipeline의 pipeline.py에서 first=0 TODO를 교체합니다. 기존 blocked·always 조건은 유지합니다.
first=first or rc실패 주입과 정책 검사를 나누어 실행합니다
bash check.sh가 정책 다섯 검사를 통과한 뒤 합성 계획을 실행합니다. 두 번째 명령은 의도한 실패 7입니다. reports/pipeline.json의 UI SKIPPED와 공통 단계 PASS를 확인합니다.
bash check.sh
python3 pipeline.py plan.json정리 실패도 함께 보고합니다
두 오류가 있는 배열을 그대로 실행하여 최초 실패와 추가 오류를 별도로 유지하는 표현을 봅니다.
results=[{'name':'ui','exit':4},{'name':'cleanup','exit':8},{'name':'publish','exit':0}]
print('final:',next(x['exit'] for x in results if x['exit']))
print('failed:',','.join(x['name'] for x in results if x['exit']))실행 결과
final: 4 failed: ui,cleanup
확인 문제
실습
pipeline.py의 첫 실패 저장 TODO를 완성합니다. 정상·API 실패·정리 추가 실패·publish 실패·명령 없음 다섯 검사를 통과합니다. 합성 계획은 UI SKIPPED와 정리·publish 호출을 보이면서 종료 7을 유지해야 합니다.
실행 명령
bash check.sh
기대 결과
정책 다섯 검사 통과; plan.json 별도 실행은 종료 7
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 실행 순서에 따라 결과가 달라지는 테스트를 확인하는 방법을 설명해 주시면 됩니다.