가끔 실패하는 테스트를 재시도로 덮지 않았습니다
혼자 돌리면 통과하고 전체를 돌리면 실패하는 테스트가 있었습니다. 재시도를 켜면 사라지는데, 켜지 않기로 했습니다.
안녕하세요. 오픈소프트랩 개발팀입니다.
단위 테스트 400건이 전부 통과하는데 서비스는 깨져 있었다는 글을 쓴 적이 있습니다. 그 뒤로 화면을 실제로 열어보는 테스트를 늘렸습니다.
늘리고 나서 다른 문제가 생겼습니다. 가끔 실패합니다.
다시 돌리면 통과했습니다
증상은 이랬습니다.
전체 테스트를 돌리면 한 건이 실패합니다. 그 한 건만 따로 돌리면 통과합니다. 다시 전체를 돌리면 이번엔 통과하고, 그다음엔 또 실패합니다.
이런 테스트를 흔히 플레이키(flaky) 하다고 부릅니다. 결과가 일정하지 않은 테스트입니다.
처음 대응은 다들 하는 대로였습니다. 다시 돌렸습니다. 두 번째에 통과하면 넘어갔습니다.
재시도를 켜려다 멈췄습니다
몇 번 반복되니 손으로 다시 돌리기가 번거로워졌습니다. 테스트 도구에는 실패하면 자동으로 다시 시도하는 설정이 있습니다. 그걸 켜면 이 문제는 화면에서 사라집니다.
켜기 직전에 한 가지가 걸렸습니다.
재시도로 통과한 것과 처음부터 통과한 것을 구분할 수 있는가. 로그를 보면 구분되긴 합니다. 그런데 매일 보는 사람은 없습니다. 초록색으로 표시되면 넘어갑니다.
그러면 이렇게 됩니다. 이 테스트는 앞으로도 절반쯤 실패하는데, 아무도 모릅니다. 그리고 나중에 진짜 결함으로 실패해도 재시도가 한 번 더 돌려줍니다. 두 번 다 실패해야 알게 됩니다.
400건 글에서 정리한 것과 같은 모양이었습니다. 그때는 확인 대상으로 정하지 않은 영역이 비어 있었고, 이번엔 확인은 하는데 결과를 안 믿어도 되는 상태를 만들려던 참이었습니다.
그래서 켜지 않고 원인을 찾아보기로 했습니다.
시간을 더해봤습니다
먼저 언제 실패하는지 세어봤습니다. 네 번 돌려서 두 번 실패했습니다. 절반입니다. 우연이라고 보기엔 잦습니다.
그다음 조건을 갈랐습니다.
| 어떻게 돌렸나 | 결과 |
|---|---|
| 그 테스트만 단독으로 | 통과 |
| 전체를 하나씩 순서대로 | 통과 |
| 전체를 동시에 여러 개씩 | 간헐 실패 |
동시에 돌릴 때만 실패합니다. 동시에 돌리면 서버가 여러 요청을 한꺼번에 받으니 응답이 느려집니다. 여기까지는 예상했는데, 그래서 왜 실패하는지가 안 보였습니다.
그래서 이 테스트가 기다리는 시간을 전부 적어봤습니다.
화면 열기 최대 30초
등록 버튼 기다리기 최대 15초
모달 뜨기 기다리기 최대 15초
목록 갱신 기다리기 최대 10초
─────────────────────────
합계 최대 70초
테스트 전체 제한 시간 30초단계별 최대 대기 시간(타임아웃)을 다 더하면 70초인데, 테스트 전체 제한 시간은 30초였습니다.
혼자 돌릴 때는 각 단계가 1~2초에 끝나니 30초 안에 들어옵니다. 동시에 돌리면 첫 단계에서만 20초 넘게 쓰고, 그 뒤 단계들은 시작도 못 한 채 전체 시간이 끝납니다.
테스트가 잘못된 게 아니었습니다. 시간 배분이 애초에 맞지 않았습니다. 혼자 돌릴 때 통과한 게 운이 좋았던 쪽입니다.
제한 시간을 실제 소요에 맞췄습니다
고친 건 하나입니다. 이 테스트의 제한 시간을 실제로 걸리는 만큼으로 늘렸습니다.
그리고 세 번 연속으로 전체를 돌려 확인했습니다. 세 번 다 통과했습니다.
간단한 수정입니다. 다만 재시도를 켰다면 여기까지 오지 않았습니다. 증상이 사라졌을 테니까요. 그리고 같은 종류의 문제가 다른 테스트에도 있는지 볼 이유도 없었을 겁니다.
얻은 것과 포기한 것
얻은 것 — 테스트 결과를 그대로 믿을 수 있게 됐습니다. 빨간색이면 진짜 문제입니다. 이게 되어야 테스트를 늘리는 게 의미가 있습니다. 믿을 수 없는 테스트는 많을수록 방해가 됩니다.
그리고 숫자로 확인하는 습관이 하나 생겼습니다. "가끔 실패한다"가 아니라 "네 번 중 두 번 실패한다"로 적으면 우연인지 아닌지가 바로 보입니다.
포기한 것 — 시간이 들었습니다. 재시도 설정 한 줄이면 끝날 일을 며칠에 걸쳐 봤습니다. 급한 배포 앞이었다면 같은 선택을 했을지 모르겠습니다.
그리고 테스트 전체가 느려졌습니다. 제한 시간을 늘렸으니 정말 문제가 생겼을 때 그만큼 더 기다렸다가 실패합니다.
제한 시간을 늘리는 게 답이 아닐 때
지금 붙어 있는 문제입니다.
이번엔 제한 시간을 늘리는 게 맞았습니다. 애초에 배분이 틀려 있었으니까요. 그런데 이 방법을 계속 쓰면 위험합니다. 제한 시간을 늘려서 통과시키는 일이 반복되면, 앱이 실제로 느려진 것을 테스트가 못 잡습니다.
느려짐도 결함입니다. 화면이 열리는 데 20초 걸리면 사용자는 고장으로 받아들입니다.
그래서 두 가지를 나누기로 했습니다. 테스트가 통과하는 제한 시간와 사용자가 참을 수 있는 시간은 다른 숫자입니다. 지금은 앞쪽만 있습니다.
뒤쪽을 따로 재는 쪽을 만들고 있습니다. 테스트를 통과시키는 기준과 별개로 각 단계가 실제로 몇 초 걸렸는지를 기록해 두고, 그 값이 이전보다 눈에 띄게 늘면 알리는 방식입니다. 통과 여부와 분리하면 제한 시간을 넉넉히 두면서도 느려짐을 볼 수 있습니다.
먼저 자주 쓰는 화면 몇 개부터 재고 있습니다. 어느 정도 쌓여야 "눈에 띄게 늘었다"의 기준을 잡을 수 있어서, 당분간은 값만 모으는 단계입니다.
오픈소프트랩 개발팀이 작성합니다. 보안 운영 포탈과 생성형 AI 사용 통제를 만들고 있습니다.