실패했는데 종료 코드는 0 이었다 · 버그를 시험으로 못 박는다 · 실습
실패를 시험으로 못 박는다
목표
결함이 있는 로그 회전 도구를 pytest 로 재현하고 고친다 — 순수 함수 시험, tmp_path, 실패하는 시험 먼저, parametrize, capsys, monkeypatch, JUnit 보고서.
왜 중요한가
고쳤다는 말은 증거가 아니다. 버그를 재현하는 시험은 고치기 전에는 실패하고 고친 뒤에는 통과하며, 그 뒤로는 같은 버그가 돌아오는 것을 막는다. 파일·시간·출력에 의존하는 운영 도구는 tmp_path·monkeypatch·capsys 로 그 의존을 시험 안에 가둔다. 이 실습의 채점기는 여러분의 시험 파일을 원본 결함 코드에도 대고 돌려, 시험이 진짜로 버그를 잡는지 양방향으로 확인한다.
재료: /opt/fixtures/pyops/buggy/rotate.py — rotate.py DIR --keep N [--dry-run] [--older-than-days D]. plan(files, keep) 은 지울 파일 목록을 돌려주는 순수 함수이고, main(argv) 는 정수를 돌려준다. 결함 두 개: (1) keep 보다 하나 더 남긴다, (2) --dry-run 인데 지운다.
단계
1. mkdir -p /root/pyops/test && cp /opt/fixtures/pyops/buggy/rotate.py /root/pyops/test/ 로 복사하고, /root/pyops/test/test_rotate.py 에 plan() 을 직접 부르는 시험 하나를 쓴다. keep 이 파일 수보다 크면 빈 목록이어야 한다. pytest -q 가 통과한다.
2. tmp_path 에 .log 파일 5개를 만들고 rotate.main([str(tmp_path), "--keep", "3"]) 뒤 3개가 남는지 확인하는 시험을 쓴다. 함수 이름에 keep 이 들어가야 한다. 이 시험은 지금 코드에서 실패해야 한다(재현).
3. rotate.py 의 plan() 을 고쳐 keep 개만 남게 한다. pytest -q 가 전부 통과한다.
4. tmp_path 에 파일 2개를 만들고 --keep 0 --dry-run 뒤에도 2개가 그대로인지 확인하는 시험을 쓴다(함수 이름에 dry 포함). 원본 코드에서는 실패해야 하고, rotate.py 를 고쳐 통과시킨다.
5. keep 을 0·1·3·10 으로 바꿔 가며 남는 파일 수가 min(5, keep) 인지 확인하는 시험을 @pytest.mark.parametrize 로 쓴다. pytest --collect-only -q 에 [ 가 붙은 ID 가 4개 이상 보여야 한다.
6. capsys 로 delete <파일이름> 이 표준 출력에 찍히는지 확인하는 시험을 쓴다(함수 이름에 output 포함, capsys 사용).
7. monkeypatch 로 rotate.time.time 을 고정한 뒤 --older-than-days 7 이 8일 된 파일만 지우고 하루 된 파일은 남기는지 확인하는 시험을 쓴다(함수 이름에 older 포함, monkeypatch 사용). 파일의 수정 시각은 os.utime 으로 맞춘다.
8. pytest -q --junitxml=/root/pyops/test/report.xml 로 보고서를 남긴다. 시험이 7개 이상이고 failures 와 errors 가 0 이어야 한다.
참고
- 시험 파일은
/root/pyops/test/안에서pytest -q로 돌린다. rotate.py 와 같은 디렉터리에 있으면import rotate가 된다. - 8일 전 시각:
os.utime(path, (t, t))에t = FIXED - 8 * 86400을 넣는다. FIXED 는 monkeypatch 로 time.time 이 돌려주게 한 값이다. - 흔한 실수: 실제 시간을 기다리는 sleep, 고정 경로 /tmp 사용, 고치기 전에 실패하는지 확인하지 않는 것.
단계 8개
- 순수 함수부터 시험한다
- 실패하는 시험으로 재현한다
- 고치고 초록을 확인한다
- 두 번째 결함도 같은 순서로
- 입력 여러 벌을 한 시험으로
- 출력도 계약이다
- 시간을 갈아 끼운다
- 기계가 읽을 보고서