Devin.KR

제품·환경·테스트 실패 구분

100분 안팎

학습 목표

로그와 재현 증거로 실패를 분류합니다.

개념

빨간 결과만으로 담당자를 정하지 않습니다

프로필 저장 테스트가 실패했다는 사실은 조사 시작점입니다. 제품이 잘못된 값을 반환했을 수도 있고 앱이 뜨지 않았을 수도 있으며 테스트가 옛 버튼 이름을 찾았을 수도 있습니다. 이 세 경우는 같은 빨간 표시여도 다음 행동이 다릅니다. 원인 분류는 책임을 떠넘기는 라벨이 아니라 가장 먼저 확인할 증거를 고르는 작업입니다.

제품 실패는 합의한 기대와 관찰한 업무 결과가 어긋난 경우입니다. 환경 실패는 검사를 수행하기 위한 연결·실행 조건이 충족되지 않은 경우입니다. 테스트 실패는 잘못된 선택자나 기대값처럼 검사 자체가 계약을 잘못 표현한 경우입니다. 증거가 부족하거나 서로 충돌하면 UNKNOWN으로 남깁니다. 모든 실패를 세 칸 중 하나에 억지로 넣지 않습니다.

이번 브라우저 실습은 표준 입력의 JSON 한 건을 읽고 분류와 근거 코드를 한 줄 출력합니다. 실제 브라우저나 네트워크를 호출하지 않습니다. 입력은 이미 조사된 합성 기록이라는 계약을 가집니다. 출력은 그 기록에 대한 규칙 적용이며 실제 앱의 원인이 확정되었다는 증거가 아닙니다.

연결 거절과 응답 실패를 나눕니다

ECONNREFUSED는 이번 합성 기록에서 연결을 맺지 못했다는 transport 값입니다. status가 null이고 appLog가 false이면 HTTP 응답과 앱 처리 증거가 없는 조합입니다. ENVIRONMENT NO_CONNECTION을 반환하고 앱 준비 여부와 주소·포트 조건을 다음 조사로 잡습니다. 앱이 요청을 받지 않은 상태에서 응답 본문 결함을 단정할 수 없습니다.

HTTP 503은 연결 거절과 다릅니다. 응답을 보낸 구성 요소가 있다는 증거이며 제품·프록시·외부 의존성 중 어디서 생성했는지 더 확인해야 합니다. 이 실습의 규칙에는 503 자동 분류가 없으므로 UNKNOWN MORE_EVIDENCE입니다. 상태 코드 하나만으로 환경 실패라고 찍으면 제품의 잘못된 오류 처리나 프록시 구성을 놓칠 수 있습니다.

시간 초과도 같은 기준을 적용합니다. 기다린 조건이 연결인지 응답인지 locator 표시인지 읽어야 합니다. transport가 TIMEOUT이고 앱 로그가 없다는 기록만으로 네트워크 원인을 확정하지 않습니다. 요청 시각·서버 준비·선택 대상·전송 여부를 추가로 확인합니다. 증거 부재를 특정 원인의 증명으로 바꾸지 않는 연습입니다.

제품 계약 불일치를 확인합니다

제품 분류 규칙은 status가 숫자 200이고 oracle이 true이며 contractMatch가 false인 조합입니다. oracle은 기대값이 합의한 요구와 독립적으로 확인되었다는 합성 표시입니다. 200은 전송된 응답 상태가 성공이라는 뜻이며 닉네임 저장이나 응답 본문의 정확성을 대신하지 않습니다. 독립 기대값과 실제값의 차이가 조사 근거입니다.

같은 200과 본문 불일치라도 oracle이 false이면 UNKNOWN을 반환합니다. 테스트의 낡은 기대값이 문제일 수 있기 때문입니다. 먼저 spec의 요구사항 ID와 현재 합의, API·저장값·화면 값을 대조합니다. 기대값을 실제값으로 바꿔 일치시키면 검사는 초록색이 되어도 계약 검증의 독립성이 사라집니다.

미션의 product fixture는 계약 일치 단언을 실패시키고 withFixture의 정리가 끝난 뒤 제품 후보로 분류합니다. appLogPresent와 요청 ID가 보고서에 있습니다. 여기서 true는 합성 기록의 조건이지 실제 운영 로그를 조회했다는 의미가 아닙니다. 실제 조사 기록을 작성할 때에는 접근 가능한 원본 로그 위치와 시간 범위를 별도로 연결해야 합니다.

옛 locator와 화면 결함을 구별합니다

테스트 분류 규칙은 응답과 계약이 정상이고 DOM 이름은 저장하기인데 locatorName은 저장하기구버전인 조합입니다. 합의한 화면 이름이 유지되고 테스트만 옛 이름을 찾는다는 제공 근거가 있어 TEST STALE_LOCATOR를 출력합니다. 현재 DOM이 실제로 존재하고 올바른 영역에 있는지 확인하는 과정이 먼저입니다.

모든 locator timeout을 테스트 문제로 취급하지 않습니다. 로그인 실패로 프로필이 숨겨졌다면 선택자는 올바르게 기다리고 있는 것일 수 있습니다. 제품이 버튼을 렌더하지 못한 경우도 있습니다. 이름 두 문자열이 다르다는 사실만으로 합의한 변경 여부를 알 수 없으므로 미지의 새 이름 조합은 UNKNOWN으로 남깁니다.

stale locator를 고칠 때에는 요구된 버튼 역할과 이름을 다시 선택하고 같은 흐름을 실행합니다. timeout을 늘리거나 첫 요소를 고르는 우회는 잘못된 이름 계약을 해결하지 않습니다. 보고서에는 화면 계약이 유지된 근거와 수정한 검사 줄, 수정 후 관찰을 적습니다. 테스트 수정도 제품 변경처럼 검토 가능한 증거가 필요합니다.

규칙의 입력 타입과 순서를 지킵니다

JSON의 status는 숫자 또는 null입니다. 문자열 200은 숫자 200으로 자동 변환하지 않습니다. 기록 수집기가 잘못된 타입을 전달했다면 UNKNOWN으로 남겨 데이터 계약을 조사합니다. 숫자 문자열을 받아 주는 편의 수정은 기록 결함을 숨길 수 있습니다. 표준 입력은 JSON 객체 한 건이며 배열·여러 건 처리 기능은 이번 범위 밖입니다.

분류 함수는 근거가 좁고 명확한 실패 규칙을 먼저 확인하고 마지막에 PASS와 UNKNOWN을 둡니다. PASS는 exit가 0이고 contractMatch가 true인 제공 조합입니다. 계약이 맞더라도 locator 실패로 exit가 1이면 PASS가 아닙니다. 부분 성공 사실을 전체 통과로 확대하지 않도록 종료 결과와 업무 계약을 함께 읽습니다.

빈 객체에는 연결·응답·기대 확인이 없으므로 UNKNOWN입니다. 잘못된 JSON 문법은 입력 계약 오류로 러너에서 실패하게 하고 분류의 UNKNOWN과 구별합니다. 이번 테스트 입력은 모두 유효 JSON이므로 JSON.parse 예외를 임의로 삼켜 UNKNOWN을 출력하는 코드를 넣을 필요가 없습니다. 입력 형식 오류와 조사 부족의 상태가 다릅니다.

오류 메시지를 근거 코드로 바꿉니다

실습의 출력은 PRODUCT CONTRACT_MISMATCH처럼 분류와 근거 두 토큰입니다. 메시지 원문을 그대로 출력하지 않습니다. 원문에는 이메일·쿠키·파일 경로가 섞일 수 있어 공개 요약으로 부적절합니다. 근거 코드는 관찰 유형을 압축하며 실제 재현 절차와 제한된 원본 로그를 대체하지 않습니다.

미션 replay는 실제로 단언 또는 오류를 발생시킨 다음 비정상 종료합니다. report의 error는 CONTRACT_ASSERTION·ECONNREFUSED·LOCATOR_NOT_FOUND와 같은 허용 코드입니다. 요청 요약은 앞 모듈의 publicLog를 재사용하여 password와 임의 필드를 버립니다. 분류에 필요한 사실과 공개 가능한 증거의 범위를 함께 설계합니다.

오류 수집 뒤 프로세스가 0으로 끝나면 실패 주입 검사가 실패합니다. fixture마다 기대한 종료 코드와 보고서 분류, 정확한 근거 코드, 정리 여부를 모두 비교합니다. 글로 제품이라고 적은 보고서를 만드는 것만으로 검증이 끝나지 않습니다. 실패를 검출하고 전파한 실행 결과가 보고서의 판단과 일치해야 합니다.

분류 뒤 다음 행동을 남깁니다

제품 후보에는 응답 생성과 저장값 대조를 제안하고 환경 후보에는 앱 준비와 주소 확인을 제안합니다. 테스트 후보에는 합의한 이름으로 locator 수정을 제안합니다. UNKNOWN에는 독립 재현과 추가 증거 수집을 적습니다. 다음 조치가 구체적이면 담당자가 첫 조사에서 어떤 파일과 관찰값을 봐야 하는지 알 수 있습니다.

분류 기록에는 실행 버전, 실패 ID, 요청 ID, 기대값 출처, 관찰 사실, 잠정 분류, 다음 조치를 함께 남깁니다. 증거가 늘어나면 잠정 분류를 수정할 수 있습니다. 처음부터 원인을 확정한 표현을 쓰면 반대 증거를 놓치기 쉽습니다. 예를 들어 앱 로그가 나중에 발견되면 연결 거절 기록이 같은 요청인지부터 확인합니다.

브라우저 실습의 경계 입력은 근거 없는 불일치, 미지의 시간 초과, 숫자 문자열, 빈 객체입니다. 네 입력 모두 자동 확정이 위험한 상황을 연습합니다. 로그의 일반 필드 설계는 더 읽기로 이어가고 여기서는 어떤 조합에서 판단을 멈추는지 설명합니다. 완료 기준은 정상 네 조합과 근거 부족 경계 조합을 같은 규칙으로 통과하는 것입니다.

따라하기

기대값 확인 여부를 읽습니다

입력 두 건은 같은 응답 상태이지만 독립 기대 확인이 다릅니다. 실제 API 요청 없이 규칙의 증거 조건을 계산합니다.

for (const r of [{status:200,oracle:true,contractMatch:false},{status:200,oracle:false,contractMatch:false}]) console.log(r.oracle===true ? '제품 후보: 독립 기대 확인' : '보류: 기대 출처 확인');

실행 결과

제품 후보: 독립 기대 확인
보류: 기대 출처 확인

연결 기록의 의미를 확인합니다

연결 거절 기록은 HTTP 응답 코드와 앱 처리 증거가 없다는 계약입니다. null을 0 또는 문자열로 바꾸지 않습니다.

const r={transport:'ECONNREFUSED',status:null,appLog:false};console.log('HTTP response:',r.status===null?'없음':'있음');console.log('app log:',r.appLog?'있음':'없음');

실행 결과

HTTP response: 없음
app log: 없음

판단을 보류할 경계를 실행합니다

숫자 200과 문자열 200을 엄격히 비교하고 부족한 입력에서 확정 조건을 만들지 않습니다.

for (const status of [200,'200',null]) console.log(JSON.stringify(status),status===200?'숫자 200':'확정 조건 아님');

실행 결과

200 숫자 200
"200" 확정 조건 아님
null 확정 조건 아님

분류 함수를 완성합니다

실습 입력의 유효 JSON 객체 한 건을 읽습니다. 출력은 두 토큰이며 빈 객체·미지의 timeout·독립 기대 없는 불일치에 UNKNOWN MORE_EVIDENCE를 반환합니다. 아래는 입력 예시이며 코드가 아닙니다.

{"status":200,"oracle":true,"contractMatch":false,"exit":1}

확인 문제

실습

표준 입력은 유효 JSON 객체 한 건입니다. status는 숫자 또는 null이며 잘못된 타입은 확정하지 않습니다. transport=ECONNREFUSED·status=null·appLog=false이면 ENVIRONMENT NO_CONNECTION, status=200·oracle=true·contractMatch=false이면 PRODUCT CONTRACT_MISMATCH입니다. status=200·contractMatch=true·domName=저장하기·locatorName=저장하기구버전이면 TEST STALE_LOCATOR입니다. exit=0·contractMatch=true이면 PASS VERIFIED, 나머지는 UNKNOWN MORE_EVIDENCE입니다. 앞 실패 규칙을 PASS보다 먼저 적용합니다. 두 토큰을 한 줄로 출력하세요.

모범 답안
const fs=require('node:fs');
const r=JSON.parse(fs.readFileSync(0,'utf8'));
let result;
if(r.transport==='ECONNREFUSED' && r.status===null && r.appLog===false)result='ENVIRONMENT NO_CONNECTION';
else if(r.status===200 && r.oracle===true && r.contractMatch===false)result='PRODUCT CONTRACT_MISMATCH';
else if(r.status===200 && r.contractMatch===true && r.domName==='저장하기' && r.locatorName==='저장하기구버전')result='TEST STALE_LOCATOR';
else if(r.exit===0 && r.contractMatch===true)result='PASS VERIFIED';
else result='UNKNOWN MORE_EVIDENCE';
console.log(result);

더 읽기

면접 질문

  • API 응답 코드가 성공이어도 테스트가 실패할 수 있는 상황을 설명해 주시면 됩니다.