dev.to

1,558 Tests Green and No Auth: The Tests That Never Actually Ran

테스트 1,558개가 통과했지만 인증은 없었습니다 — 실제로 실행되지 않은 테스트들

테스트가 모두 통과했다는 결과가 실제 검증을 의미하지 않을 수 있음을 세 가지 사례로 보여줍니다. 빈 테스트 본문, 0/0을 성공으로 처리한 하네스, import 오류를 삼켜 인증 검사를 건너뛴 사례를 통해 실행·검증 여부를 CI가 직접 확인해야 한다고 제안합니다.

AI 요약

이 글은 녹색 테스트 결과를 신뢰하기 전에 테스트가 실제로 실행되었고 assertion도 수행했는지를 확인해야 한다고 주장합니다. 문제는 테스트가 실패하지 않았다는 사실 자체가 아니라, 테스트가 아예 실행되지 않았는데도 성공으로 보고될 수 있다는 점입니다. 글에서는 서로 다른 저장소와 상황에서 발견된 세 가지 사례를 통해, 테스트 스위트의 녹색 상태가 시스템의 안전성을 보장하지 못하는 과정을 설명합니다.

■ 아무것도 검증하지 않는 테스트 본문

planner-critic-engine에는 모든 adapter가 import 가능한지를 확인한다는 이름의 `test_all_adapters_importable()` 테스트가 있었습니다. 하지만 함수 본문은 `pass`뿐이었습니다. 주석에는 import되었다면 괜찮다는 취지가 적혀 있었지만, 실제로는 import를 수행하지도 않았고 어떤 assertion도 포함하지 않았습니다. 따라서 모든 adapter가 망가져도 이 테스트는 영원히 통과할 수 있는 상태였습니다. 이 문제는 CI가 발견한 것이 아니라 코드 리뷰에서 사람이 파일을 읽다가 발견했습니다. 글은 이 문제가 Issue #236으로 기록되었으며, LLM sweep이 시작되기 전에 사람이 확인했다는 점을 함께 언급합니다. 테스트 이름이 검증 의도를 설명하고 있어도, 실행 코드가 없으면 테스트 결과는 아무것도 증명하지 못합니다.

■ 0/0을 성공으로 처리한 테스트 하네스

같은 저장소에서는 assertion 파일 65개 가운데 57개가 하네스가 기대하는 형식과 달랐습니다. 하네스는 파일을 파싱했지만 실행할 assertion을 하나도 찾지 못했고, 결과를 `0 / 0`으로 반환했습니다. 더 큰 문제는 이 상태를 오류가 아니라 성공으로 처리했다는 점입니다. 결과적으로 테스트 스위트는 초록색이었지만 실제로 실행한 assertion은 없었습니다. 글이 강조하는 핵심은 잘못된 형식의 파일을 작성했다는 사실보다, 실행 대상이 0개인 상태를 CI가 조용히 통과시켰다는 사실입니다. 테스트 파일이 존재하고 파싱 과정도 지나갔다는 것만으로는 검증이 수행되었다고 볼 수 없습니다.

■ import 오류가 숨긴 인증 검사

CauterRule v0.3.0에서는 테스트 1,558개가 모두 통과한 것으로 보고되었습니다. 그러나 MCP HTTP bearer-auth guard는 실제로 실행되지 않았습니다. 해당 guard를 불러오는 import가 내부에서 삼켜졌기 때문입니다. 그 결과 모든 unit test가 통과했지만, 인증되지 않은 요청이 store를 읽을 수 있는 경로가 테스트 결과에 드러나지 않았습니다. 이 unauthenticated store read를 발견한 것은 일반적인 테스트 스위트가 아니라, 실제 컨테이너에서 실제 시스템을 실행한 Docker field test였습니다. 즉, 테스트 개수가 많고 모두 녹색이라는 사실이 인증 경계를 검증했다는 의미가 아니었습니다.

■ ‘통과’와 ‘실행되지 않음’을 분리해야 합니다

세 사례에서 공통으로 드러난 문제는 테스트 실패를 놓친 것이 아니라, 테스트가 수행되지 않은 상태를 성공으로 오인했다는 점입니다. 글은 `tests/assertions/`를 실행한 뒤 결과의 `executed`와 `assertions`를 별도로 확인하는 meta-test 예시를 제시합니다. 하네스가 실행한 결과 수가 0보다 큰지 확인하고, 파싱된 assertion 수도 0보다 큰지 확인해야 합니다. 예시는 다음과 같은 조건을 둡니다.

`def test_suite_is_not_empty():` ` results = run_assertion_files("tests/assertions/")` ` assert results.executed > 0, "harness ran zero assertions"` ` assert results.assertions > 0, "assertions parsed to empty set"`

이에 따라 글은 두 가지 규칙을 제안합니다. 첫째, 어떤 모듈이든 결과를 0개 내놓으면 CI가 실패해야 합니다. `0 / 0`은 통과가 아니라 오류 상태로 취급해야 합니다. 둘째, ‘실행되지 않음’과 ‘실행되었고 통과함’을 구분해야 합니다. 삼켜진 import나 건너뛴 모듈은 조용히 넘어갈 상황이 아니라 명시적인 실패로 보고되어야 합니다. 이 구분이 없으면 테스트 게이트는 실제 검증을 수행하는 장치가 아니라, 검증이 사라져도 녹색을 표시하는 장치가 될 수 있습니다.

■ meta-test도 만능은 아닙니다

글은 테스트가 실제로 실행되었는지를 확인하는 meta-test 자체에도 한계가 있다고 덧붙입니다. meta-test 역시 프로세스의 일부이므로, 그 검사가 중단되거나 더 이상 제대로 확인하지 않게 되면 또 하나의 녹색 체크 표시로 전락할 수 있습니다. 또한 애초에 검증 대상으로 생각하지 못한 false negative까지 모든 테스트 규율이 잡아내는 것은 아닙니다. 따라서 제안된 검사는 ‘녹색이지만 망가진 상태’의 가장 위험한 범주, 즉 테스트가 실행되지 않았는데 모든 것이 정상이라고 알려주는 상황을 줄이는 방법이지 이를 완전히 제거하는 방법은 아닙니다.

원문은 CauterRule, CauterRule v0.3.0 field test report, PlannerCritic failure-mode register, agent-tooltrust design decisions를 관련 공개 자료로 제시합니다. 글의 결론은 테스트 개수를 늘리는 것보다 테스트가 실제로 실행되고 assertion을 수행했는지를 실패 조건으로 만드는 것이 중요하다는 것입니다. 녹색 빌드를 신뢰하려면 결과 숫자뿐 아니라 raw output과 실행 경로까지 확인해야 한다는 문제의식을 제시합니다.

원문: dev.to / 번역·요약: Trawling