검증의 관점에서 테스트 코드는 프로덕션 코드를 검증하기 위한 용도일 뿐이다.
왜냐하면 보통 테스트 코드를 작성하는 사람이 프로덕션 코드를 작성하기 때문이다. 그렇다는 것은 테스트 코드의 유무와 관계없이 잠재적 테스트 커버리지 수준은 동일하다는 의미다. 그 사람이 생각하는 범위 내에서 테스트 케이스가 정해질 것이기 때문이다. 결국 테스트 코드는 프로덕션 코드에 대한 검증을 편리하게 하여 프로덕션 코드 완성 과정의 보조 역할을 하는 것이다. 즉 테스트 코드는 프로덕션 코드를 타기팅 하고 있다.
이 말은 테스트 코드는 실제 애플리케이션(이하 앱)을 테스트하는 용도가 아니라는 것이다. 앞서 말한 테스트 커버리지는 테스트 코드가 프로덕션 코드를 얼마나 충분히 테스트하고 있는지에 대한 것이 아니다. 앱에 대한 테스트 커버리지를 의미한다. 만약 테스트 코드가 완벽한 앱 테스트를 할 수 있다면 QA 조직이 왜 필요하겠는가? 혹은 QA 조직에선 왜 모든 테스트를 자동화하려고 시도하지 않을까?
테스트 코드도 결국 코드이기 때문에 그것 자체에 대한 오류는 인지할 수 없다. 물론 이런 생각이 꼬리에 꼬리를 물면 끝이 없다. 그렇기 때문에 '버그 없는 소프트웨어는 없다'는 말이 있는 것이 아닐까?
이런 생각을 해보는 이유는 테스트 코드를 앱 테스트용으로 생각하는 경우가 있는 것 같기 때문이다. 테스트 코드로 모든 경우를 테스트할 수 없고 실제로 앱을 실행시켜서 확인하는 것이 더 빠른데 왜 테스트 코드를 작성해야 하는지 모르겠다는 의문을 품는 사람이 있다.
테스트 코드가 프로덕션 코드를 검증하기 위한 용도라는 것을 받아들인다면 관점에 따라서 프로덕션 코드가 테스트 코드를 테스트하기 위한 것일 수도 있다. 프로덕션 코드가 제대로 동작하는지 검증하기 위해 테스트 코드를 작성한다. 이것을 반대로 하면 테스트 코드가 제대로 동작하는지 검증하기 위해 프로덕션 코드를 작성한다고 볼 수 있다. 이렇게 표현하니 뭔가 TDD 같은 느낌이 있는데 실제 순서상 테스트 코드를 작성하고 프로덕션 코드를 작성한다는 것에 포인트를 두기보다는 양쪽 코드가 모두 작성된 상태에서 관점만 바꿔 보는 것이다. 그러면 프로덕션 코드를 리팩터링 해도 테스트 코드가 성공했을 때 심리적 안정감을 느끼듯이 예컨대 테스트 코드를 JUnit에서 Kotest로 바꾸는 경우처럼 테스트 코드를 수정해도 프로덕션 코드가 존재하기에 테스트 코드가 올바르게 마이그레이션 되었다고 느끼지 않을까 싶다. (테스트 코드를 개발하는 개발자들은 테스트 코드를 검증하기 위해 실제로 이와 비슷한 과정을 거치지 않을까 하는 상상도 해본다.)
이 상황을 납득할 수 없다는 생각이 드는가? 프로덕션 코드에 버그가 있을 수 있는데 그것에 맞춰 통과하는 테스트 코드가 어찌 검증된 테스트 코드가 되냐고? 그게 처음 이야기한 것과 다를 바 없는 것이다. 테스트 코드가 모두 통과되어도 여전히 가시지 않는 위협은 존재한다. 그렇기에 테스트 코드가 프로덕션 코드에 존재하는 버그를 모두 검증할 수 없다는 것이다.
그럼 왜 테스트 코드를 작성해야 하지? 여러 가지 이유가 있겠지만 아무래도 일단 잘 돌아간다고 생각되는 코드 구현에 도움을 준다. 그리고 나중에 혹은 곧바로 리팩터링을 할 때도 든든함을 제공한다. 결국 프로덕션 코드 작성을 돕는 도구일 뿐이다. 절대로 버그들을 모두 쏴 죽이는 은총알이 아니다.