LabHub
배우기 러닝패스 코스

テストツール実戦

失敗経路と副作用を分離してテストする

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

네트워크와 실제 대기 없이 호출 수·백오프·파일 보존·저장 실패를 재현합니다.

왜 중요한가

정상 요청 한 번의 성공은 경계값과 장애 복구를 보장하지 않습니다. 이 실습은 각 함수의 계약을 작게 구현하거나 테스트한 뒤 실제 실행으로 연결합니다. 코드가 존재하는지나 보고서 문구만 보지 않고 결과·예외·저장 상태를 검사합니다. 앞 단계의 코드를 유지하며 다음 단계로 진행하세요.

단계

  1. /root/work/test-failures-lab/test_service.py에서 fetch가 send의 문자열을 그대로 반환하고 send를 정확히 한 번 호출하는지 테스트하세요. cache는 tmp_path 아래 pathlib.Path로 전달합니다. 첫 준비는 다음 명령으로 합니다.
mkdir -p /root/work/test-failures-lab
cp /opt/fixtures/practice_depth/test-failures-lab/* /root/work/test-failures-lab/
cd /root/work/test-failures-lab
  1. /root/work/test-failures-lab/test_service.py에서 첫 send는 TimeoutError, 두 번째는 'fresh'를 반환하도록 구성하고 fetch가 'fresh'를 반환하는지 확인하세요.
  2. /root/work/test-failures-lab/test_service.py에서 계속 TimeoutError인 send를 넣고 총 3회 호출 뒤 TimeoutError가 전파되는지 확인하세요.
  3. /root/work/test-failures-lab/test_service.py에서 ValueError를 내는 send는 정확히 1회만 호출되고 같은 종류의 예외가 전파되는지 테스트하세요.
  4. /root/work/test-failures-lab/test_service.py에서 모든 send가 TimeoutError일 때 sleep에 전달한 값이 정확히 [0.1, 0.2]인지 검사하세요. 실제로 잠들지 않습니다.
  5. /root/work/test-failures-lab/test_service.py에서 한글 문자열로 성공시킨 뒤 cache 파일을 UTF-8로 읽어 같은 내용이 저장됐는지 확인하세요.
  6. /root/work/test-failures-lab/test_service.py에서 cache에 'old'를 미리 쓴 뒤 send를 계속 실패시키세요. 예외 후 파일 내용이 여전히 'old'인지 확인합니다.
  7. /root/work/test-failures-lab/test_service.py에서 send가 성공해도 cache 쓰기가 실패하면 OSError가 전파되는지 테스트하세요. cache에 tmp_path 디렉터리 자체를 전달하면 결정적으로 쓰기가 실패합니다.

참고

성공 경로의 불필요한 호출을 잡는다

/root/work/test-failures-lab/test_service.py에서 fetch가 send의 문자열을 그대로 반환하고 send를 정확히 한 번 호출하는지 테스트하세요. cache는 tmp_path 아래 pathlib.Path로 전달합니다. 첫 준비는 다음 명령으로 합니다.

mkdir -p /root/work/test-failures-lab
cp /opt/fixtures/practice_depth/test-failures-lab/* /root/work/test-failures-lab/
cd /root/work/test-failures-lab

calls 리스트에 기록하는 함수를 주입하세요. 반환값만 보면 중복 호출을 놓칩니다.

채점은 bash /opt/lab/checks/test-failures-lab/01-contract.sh로 직접 재현할 수 있습니다. 파일 저장 후 다시 실행하세요.

한 번 실패한 뒤 복구시킨다

/root/work/test-failures-lab/test_service.py에서 첫 send는 TimeoutError, 두 번째는 'fresh'를 반환하도록 구성하고 fetch가 'fresh'를 반환하는지 확인하세요.

iterator 또는 호출 횟수로 순서를 제어합니다. 테스트 자체에서 실제 네트워크에 접속하지 않습니다.

채점은 bash /opt/lab/checks/test-failures-lab/02-contract.sh로 직접 재현할 수 있습니다. 파일 저장 후 다시 실행하세요.

총 시도 횟수와 마지막 예외를 검사한다

/root/work/test-failures-lab/test_service.py에서 계속 TimeoutError인 send를 넣고 총 3회 호출 뒤 TimeoutError가 전파되는지 확인하세요.

재시도 3번과 총 시도 3번은 다릅니다. 이 계약은 최초 요청을 포함해 3회입니다.

채점은 bash /opt/lab/checks/test-failures-lab/03-contract.sh로 직접 재현할 수 있습니다. 파일 저장 후 다시 실행하세요.

영구 오류의 재시도를 막는다

/root/work/test-failures-lab/test_service.py에서 ValueError를 내는 send는 정확히 1회만 호출되고 같은 종류의 예외가 전파되는지 테스트하세요.

예외 종류뿐 아니라 calls 길이를 검사해야 무의미한 두 번의 추가 호출을 잡습니다.

채점은 bash /opt/lab/checks/test-failures-lab/04-contract.sh로 직접 재현할 수 있습니다. 파일 저장 후 다시 실행하세요.

백오프 수열과 마지막 대기를 확인한다

/root/work/test-failures-lab/test_service.py에서 모든 send가 TimeoutError일 때 sleep에 전달한 값이 정확히 [0.1, 0.2]인지 검사하세요. 실제로 잠들지 않습니다.

sleep 인자에 delays.append를 전달합니다. 마지막 실패 뒤에는 다음 시도가 없으므로 대기도 없어야 합니다.

채점은 bash /opt/lab/checks/test-failures-lab/05-contract.sh로 직접 재현할 수 있습니다. 파일 저장 후 다시 실행하세요.

반환값과 디스크 내용을 함께 확인한다

/root/work/test-failures-lab/test_service.py에서 한글 문자열로 성공시킨 뒤 cache 파일을 UTF-8로 읽어 같은 내용이 저장됐는지 확인하세요.

성공 결과만 반환하고 파일 쓰기를 빠뜨린 구현은 반환값 테스트만으로 잡을 수 없습니다.

채점은 bash /opt/lab/checks/test-failures-lab/06-contract.sh로 직접 재현할 수 있습니다. 파일 저장 후 다시 실행하세요.

네트워크 실패가 기존 캐시를 지우지 못하게 한다

/root/work/test-failures-lab/test_service.py에서 cache에 'old'를 미리 쓴 뒤 send를 계속 실패시키세요. 예외 후 파일 내용이 여전히 'old'인지 확인합니다.

준비 → 실행과 예외 검사 → 파일 상태 확인 순서로 구성합니다. 파일이 존재하는지만 보지 마세요.

채점은 bash /opt/lab/checks/test-failures-lab/07-contract.sh로 직접 재현할 수 있습니다. 파일 저장 후 다시 실행하세요.

저장 실패를 가짜 성공으로 바꾸지 않는다

/root/work/test-failures-lab/test_service.py에서 send가 성공해도 cache 쓰기가 실패하면 OSError가 전파되는지 테스트하세요. cache에 tmp_path 디렉터리 자체를 전달하면 결정적으로 쓰기가 실패합니다.

권한 변경에 의존하지 않는 오류를 만드세요. 성공 문자열 반환만 확인하는 테스트와 다른 책임입니다.

채점은 bash /opt/lab/checks/test-failures-lab/08-contract.sh로 직접 재현할 수 있습니다. 파일 저장 후 다시 실행하세요.