My tests were describing the code, not checking it

개요

Claude Code로 개발된 .NET 인보이스 라이브러리에서 자동 생성된 테스트가 실제 코드의 오류를 잡아내지 못하고 코드 자체의 일관성만을 확인한다는 사실을 발견한 경험에 대한 글입니다.

주요 내용

* AI 생성 테스트의 한계: Claude Code로 개발된 .NET 인보이스 라이브러리에서 20개 이상의 테스트가 통과했지만, 실제로는 3p의 오차가 발생하는 버그가 존재했습니다. 이는 AI가 코드를 구현하고 해당 코드를 테스트하는 과정에서 코드와 테스트 간의 일관성만 확인하고 실제 정확성을 검증하지 못했기 때문입니다.
* 테스트의 허점 발견:
* 속성 기반 테스트 (Property Tests)의 무력함: 손으로 계산한 값으로 구성된 골든 시나리오 테스트와 CSV 내보내기 테스트 등은 일반적인 경우를 다루었지만, 미묘한 반올림 오류를 잡아내지 못했습니다.
* 변이 테스트 (Mutation Testing)의 필요성: 의도적으로 버그를 주입하여 테스트가 실패하는지 확인하는 변이 테스트가 필요함을 깨달았습니다. Stryker.NET 사용 시 멀티 타겟 설정으로 실패했지만, 수동 변이를 통해 네 곳의 반올림 호출 지점을 집중적으로 테스트했습니다.
* 반올림 로직 검증의 불완전성: 라이브러리는 세금 계산을 위해 MidpointRounding.AwayFromZero를 사용해야 했으나, .NET 기본값인 MidpointRounding.ToEven이 적용되었습니다. 반올림 헬퍼 자체에 대한 테스트는 통과했지만, 정작 인보이스 시나리오에서는 중간값이 포함되지 않아 오류가 드러나지 않았습니다.
* CSV 내보내기 테스트의 허점: 문화별 숫자 형식 테스트 역시 실제 소수점을 포함하는 데이터를 사용하지 않아 오류를 잡아내지 못했습니다.
* 릴리스 파이프라인의 허위 통과: 프로젝트 파일의 버전 누락으로 인해 NuGet 패키지 배포 시 오류가 발생했지만, --skip-duplicate 옵션으로 오류가 무시되고 모든 단계가 녹색으로 표시되어 마치 성공한 것처럼 보였습니다.
* 설계 단계에서의 오류 방지: per-line 세금 모드 추가 시, tax-inclusive 가격 계산에서 발생하는 잔여값 문제에 대한 설계 질문을 서면으로 미리 진행했습니다. 이 과정에서 £3.99와 같은 특정 가격에서 발생하는 일정한 오차를 발견하고, 해당 기능을 구현하지 않기로 결정했습니다. 이는 코드를 먼저 작성했다면 발견하기 어려웠을 설계상의 결함을 미리 방지한 사례입니다.
* 실질적인 테스트 개선 제안:
* 수동 변이 테스트: 복잡한 도구 없이 코드의 중요 지점(예: 반올림 호출 지점)에 수동으로 변이를 주입하고 테스트를 실행하여 문제점을 파악하는 것이 효과적입니다.
* 설계 단계에서의 서면 검토: AI와 협업 시, 복잡한 비즈니스 로직이나 엣지 케이스에 대한 설계 질문은 코딩 전에 서면으로 명확히 정리하고 검토해야 합니다.

시사점

결과적으로, 통과한 테스트 스위트는 코드가 테스트와 일관성이 있다는 것을 의미할 뿐, 코드가 올바르다는 것을 보증하지 않으며, 특히 AI가 생성한 코드와 테스트의 경우 이러한 간극이 더 크게 발생할 수 있습니다. 따라서 개발자는 자동화된 테스트에 대한 맹신을 경계하고, 실제 비즈니스 로직과 엣지 케이스를 깊이 있게 검증하는 수동 테스트 및 설계 단계에서의 철저한 검토 과정을 병행해야 합니다.

원문 읽기 →
원문을 불러오는 중...

댓글

GitHub Discussions