테스트 도구 실전 · 지연 평가를 관측하는 내보내기 테스트 · 실습
지연 평가를 관측하는 내보내기 테스트
목표
행 소비 횟수·개행 이스케이프·공개 필드·응답 형식을 검증합니다.
왜 중요한가
작은 리스트로 테스트한 내보내기 코드는 정상처럼 보였지만 큰 입력을 모두 list로 바꾸며 메모리를 소진했다. 결과가 같은 것만으로 실행 방식의 계약까지 같다고 할 수 없다. 지연 소비를 눈으로 보이는 상태로 바꿔야 한다.
단계
1. /root/work/test-lazy-export-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: validate_row(row)는 dict이며 id가 bool 제외 양의 int, name이 비어 있지 않은 str일 때 row를 반환합니다. 나머지는 ValueError입니다. 추가 내부 필드는 허용합니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.
처음 한 번 준비하세요. 기존 파일은 덮어쓰지 않습니다.
mkdir -p /root/work/test-lazy-export-labtest -e /root/work/test-lazy-export-lab/service.py || cp /opt/fixtures/ten_labs/test-lazy-export-lab/service.py /root/work/test-lazy-export-lab/service.pytest -e /root/work/test-lazy-export-lab/test_service.py || cp /opt/fixtures/ten_labs/test-lazy-export-lab/test_service.py /root/work/test-lazy-export-lab/test_service.pycd /root/work/test-lazy-export-lab2. /root/work/test-lazy-export-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: project(row)는 validate_row 후 id와 name만 가진 새 dict를 반환합니다. 원본 내부 필드는 그대로 보존합니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.
3. /root/work/test-lazy-export-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: encode_line(row)는 project 결과를 ensure_ascii=False, separators=(',',':'), sort_keys=True로 JSON 인코딩하고 마지막에 '
' 한 개를 붙인 str입니다. name 안 개행은 JSON 이스케이프여야 합니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.
4. /root/work/test-lazy-export-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: validate_max(value)는 bool 제외 int 1~1000만 그대로 반환하고 그 외 ValueError입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.
5. /root/work/test-lazy-export-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: take_rows(rows, maximum)는 islice 등으로 최대 maximum개만 지연 반환하는 iterator입니다. 호출 시 maximum을 검증하며 한 번 next하면 입력을 한 번만 소비합니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.
6. /root/work/test-lazy-export-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: json_lines(rows, maximum=100)는 take_rows에서 받은 행마다 encode_line을 yield합니다. 전부 합친 문자열이나 리스트를 반환하지 않습니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.
7. /root/work/test-lazy-export-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: decode_lines(text)는 splitlines의 각 비어 있지 않은 줄을 json.loads 후 validate_row하고 리스트로 반환합니다. 빈 문자열은 [], 비어 있는 중간 줄은 ValueError입니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.
8. /root/work/test-lazy-export-lab/test_service.py에서 제공된 service.py의 다음 공개 계약을 테스트하세요: create_app(rows)는 GET /export에서 json_lines(rows, 100)을 application/x-ndjson StreamingResponse로 반환합니다. rows는 다시 순회 가능한 리스트입니다. 내부 필드가 없고 각 행의 내용과 순서를 보존해야 합니다. 정상 구현에서는 통과하고 이 계약을 어긴 구현에서는 실제 테스트 본문의 실패로 검출해야 합니다. 앞 단계 테스트를 유지하며 test_ 함수를 추가하세요.
참고
- 인터넷과 패키지 설치 없이 기존 lab-dev 환경에서 수행합니다.
- 각 단계는 45초 채점 예산 안에서 실행됩니다. 실제 sleep이나 네트워크 호출을 추가하지 마세요.
- 제출 테스트는 별도 임시 폴더에서 정상·결함 구현에 실행합니다. 정상에서는 실제 실행한 테스트가 모두 통과하고 결함에서는 테스트 본문이 실패해야 합니다. 수집 오류, 실행 0개, 전부 건너뜀, 강제 종료는 통과가 아닙니다. pytest 기본 기능과 제공 라이브러리만 사용하세요.
- [FastAPI 공식 문서](https://fastapi.tiangolo.com/) · [pytest 공식 문서](https://docs.pytest.org/en/stable/) · [Python sqlite3](https://docs.python.org/3/library/sqlite3.html)
- 한계: TestClient는 응답을 버퍼링하므로 네트워크 첫 바이트 지연이나 메모리 상한 전체를 증명하지 않는다. 지연 평가 여부는 별도의 계수 생성기로 검사한다. 스트림 시작 이후 잘못된 행을 만나면 정상 오류 JSON으로 상태를 바꾸기 어렵다. 실서비스는 사전 검증·행별 오류 형식·중단 정책 중 무엇을 택할지 정해야 한다. 제공 구현은 읽어도 되지만 채점은 별도 사본을 사용한다. 소스 문구 검사나 파일 수정으로 결함을 우회하지 말고 공개 인터페이스의 실행 결과를 검사한다.
8단계
- 행 계약을 검증한다 — 테스트
- 공개 행만 만든다 — 테스트
- 줄 경계를 보존하며 인코딩한다 — 테스트
- 출력 개수 상한을 검증한다 — 테스트
- 필요한 행만 소비한다 — 테스트
- 행을 지연 직렬화한다 — 테스트
- 내려받은 줄을 다시 검증한다 — 테스트
- HTTP 다운로드를 완성한다 — 테스트