소프트웨어 개발에서 가장 널리 사용되는 테스트 기법인 유닛 테스트(Unit Test)가 사실은 버그를 찾아내는 데 그리 효과적이지 않다는 흥미로운 주장이 제기되었습니다. 하드웨어 개발 경험이 풍부한 한 프로그래머는 유닛 테스트가 업계의 유일한 보편적 테스트 방법이 된 진짜 이유는 버그 탐지보다는 '코드 영역 표시'에 있다고 분석했습니다. 소프트웨어는 '나중에 고치면 된다'는 문화로 버그가 있는 코드도 출시되는 경향이 강한 반면, 하드웨어는 버그가 치명적이기에 훨씬 엄격한 테스트를 거친다는 점을 지적하며 소프트웨어 테스트의 특수성을 강조합니다.
저자는 유닛 테스트가 버그를 잘 잡지 못하는 두 가지 주요 이유를 제시합니다. 첫째, 복잡한 버그나 성능 문제는 대부분 여러 컴포넌트(component) 간의 상호작용에서 발생하므로, 전체 시스템을 함께 검증하는 통합 테스트(Integration Test)가 필수적입니다. 하지만 개발자들은 자신의 유닛(unit) 밖을 건드리지 않기 위해 의존성 모킹(mocking)에 과도하게 의존하며 통합 테스트를 소홀히 하는 경향이 있습니다. 둘째, 까다로운 버그를 찾으려면 방대한 입력 조합이 필요한데, 유닛 테스트는 소수의 하드코딩된 입력과 출력에 의존합니다. 하드웨어 업계에서는 무작위 입력 생성(random input generation)이 일반적이며, 이를 통해 입력 분포와 올바른 출력 판별 방법을 깊이 고민하는 반면, 소프트웨어 유닛 테스트의 기대 출력은 단순히 코드를 돌려 나온 값을 '정답'으로 삼는 경우가 많다는 것입니다.
그렇다면 유닛 테스트는 왜 이토록 보편화되었을까요? 저자는 그 주된 용도가 '남들이 내 코드를 함부로 망가뜨리지 못하게 막는 것'이라고 설명합니다. 코드 소유권이 모호하고(소위 '공유 소유권') 모든 개발자가 모든 것을 바꾸도록 독려받는 문화에서, 유닛 테스트는 일종의 사회적 가드레일 역할을 합니다. 쓰기 쉽고, 비용이 적게 들며, 실행 속도가 빨라 커밋 게이트(commit gate)에 포함되어도 반발이 적습니다. 또한, 조직이 품질에 지불할 의향이 있는 최소한의 비용으로 '품질' 체크박스를 채워주는 동시에, 다른 사람의 테스트를 임의로 삭제하거나 통과시키기 위해 조작하는 것이 매우 부적절한 행위로 인식되어 결국 테스트를 통과시키거나 작성자와 협의하게 만드는 메커니즘을 제공합니다. 이는 경영진과 개발자 모두를 만족시키는 균형점으로, 테스트 없이 무작정 빠르게 달리다가 발생하는 피해를 복구하는 것보다 실제로는 더 빠른 개발 속도를 가능하게 합니다.
이러한 관점에서 유닛 테스트가 코드 크기를 대략 두 배로 늘리는 이유도 설명됩니다. 핵심 코드는 공유 소유권 문화에서 누구나 변경할 수 있지만, 테스트라는 형태로 한 번 더 작성해두면 다른 개발자들이 함부로 수정하기 어렵게 됩니다. 이는