앱들끼리 서로를 홍보하는 배너가 있습니다. 원격 JSON에 홍보 항목을 적어두면 각 앱이 조건에 맞는 것 하나를 골라 그립니다.
몇 주 전에 이 설정이 조용히 망가진 적이 있어서 테스트를 하나 붙였습니다.
플릿의 모든 앱이 그릴 프로모를 하나씩 갖는다
초록불이었습니다. 계속 초록불이었고, 그 사이 홍보 항목이 10개에서 21개로 늘었습니다.
당신의 커버리지 테스트는 어느 방향으로 셉니까?
반대로 세어봤습니다
선택 로직은 조건을 통과하는 첫 번째 항목을 그립니다. 그래서 어떤 항목은 앞줄에 선점당해 영영 안 뽑힐 수 있습니다.
앱 기준이 아니라 항목 기준으로 세어봤습니다.
21개 항목 중 도달 0 : 8개인벤토리의 38%가 죽어 있었습니다. 그리고 하필 그 8개가 방금 출시한 신규 앱들의 홍보였습니다.
왜 테스트가 통과했나
테스트는 앱 → 프로모 방향입니다. 모든 앱이 뭔가를 보기만 하면 초록입니다.
항목을 아무리 추가해도, 그 항목이 아무에게도 안 보이는 상태를 이 테스트는 잡지 못합니다. 두 방향은 서로를 함의하지 않습니다.
- 모든 앱이 볼 것이 있다 → 참
- 모든 항목이 보일 곳이 있다 → 거짓
원인은 둘이었습니다
타깃이 유령이었습니다. 어떤 항목은 배너를 아예 싣지 않는 앱을 타깃으로 지정하고 있었습니다. 설정 파일에 앱 이름이 적혀 있으면 그 앱이 배너를 그린다고 착각하기 쉽지만, 그건 다른 문제입니다. 네 개가 그 상태였습니다.
타깃이 겹쳤습니다. 한 앱을 여러 항목이 노리면 앞줄이 선점합니다. 어떤 항목은 타깃 넷 중 둘이 유령이고 나머지 둘은 다른 항목이 먼저 가져가서, 결과적으로 도달 0이었습니다.
여기서 선택이 갈립니다
고치는 방법은 둘입니다. 선택 로직을 바꿔 여러 항목을 돌아가며 보여주거나, 타깃을 서로소로 유지해 결과를 결정적으로 만들거나.
당신이라면?
저는 후자를 골랐습니다. 로테이션은 상태가 필요하고 디버깅이 어려워집니다. 타깃을 1:1로 서로소로 두면 순서와 무관하게 결과가 정해집니다. 규칙에 없는 새 앱이 빈 화면을 보지 않도록 폴백 하나만 맨 뒤에 둡니다.
그리고 반대 방향 테스트 세 개를 넣었습니다.
모든 프로모가 적어도 한 앱에 도달한다
타깃 리스트는 서로소다
타깃은 전부 배너를 싣는 앱이다목록은 측정값이 아닙니다
세 번째 테스트가 중요합니다. "이 앱이 배너를 싣는가"의 정본은 설정 파일이 아니라 코드 호출부입니다.
그리고 그걸 세는 데도 함정이 있었습니다. 컴포넌트 파일 자신의 주석에 사용 예시가 들어 있어서, 안 빼면 모든 앱이 배너를 싣고 전부 같은 출처인 것처럼 읽힙니다. 실제로 한 번 그렇게 오판했습니다.
자가진단
- 커버리지 테스트가 A → B만 보고 있지 않습니까? B → A도 세어봤습니까?
- "첫 번째 일치를 고른다"는 선택 로직이 있다면, 뒤에 선 항목이 도달 가능한지 검사합니까?
- 설정 파일의 목록과 실제 코드 호출부를 대조해 본 적이 있습니까?
솔직한 부분
이 테스트를 붙인 사람이 저입니다. 같은 결함이 재발하지 않게 하려고 만들었는데, 제가 고른 방향이 절반만 덮고 있었습니다.
테스트는 통과했는데 버튼이 아무것도 안 하던 일과 같은 계열입니다. 초록불은 "내가 검사한 것이 참"이라는 뜻이지 "기능이 동작한다"는 뜻이 아닙니다.
당신의 커버리지 테스트 하나를 고르고, 반대 방향으로 같은 문장을 써보세요. 그게 여전히 참인지 확인하는 데 5분이면 됩니다.