•
자동 테스트에 이야기하기에 앞서 인수 테스트라는 용어를 먼저 살펴보자.
◦
인수 테스트는 시스템이 비즈니스 요구사항을 만족해서 소유권을 넘기기 전에 수행하는 테스트로 인수인계하기 전 마지막으로 검증하는 테스트 단계이다.
•
인수 테스트 단계의 테스트는 일반적으로 테스트 수행 절차와 기댓값이 적힌 체크리스트로 관리된다.
◦
케이스북을 활용해서 체크리스트를 쉽게 관리할 수 있다.
•
인수 테스트를 잘못 설계하게 되는 대표적인 경우는 인수 테스트의 대부분을 수동 테스트로 구성하는 것이다.
◦
수동 테스트는 자동 테스트에 비해 비용이 더 많이 발생하기 때문에 품질을 높이기 위해 수행하는 테스트가 비용 증가로 되려 품질이 더 낮아질 수 있다.
◦
이는 테스트 절차를 사람이 직접 수행하고 결과를 눈으로 확인하는 데 많은 시간과 노력이 들기 때문이다.
•
물론 인수 테스트 과정을 수동 테스트로 채우는 것이 어찌 보면 당연하다. 최종 사용자에게 소프트웨어를 전달하기 전, 마지막 테스트 단계이기 때문에 사용자의 입장에서 테스트를 해볼 필요가 있는 것이다.
◦
그러나 시스템의 모든 테스트가 사람의 손을 반드시 거쳐야만 하는 이유는 없다. 일부는 자동 테스트를 사용해서 충분히 대체될 수 있다.
•
또한 수동 테스트의 한 가지 문제점은 테스트가 누적된다는 것이다. 시스템에 업데이트가 생겼을 때, 기존의 테스트가 정상적으로 돌아갈 것이라는 보장이 없다. 따라서 기존의 테스트들도 수행해주어야 하기때문에 누적된다.
1. Regression
•
회귀라는 뜻으로 소프트웨어 개발 분야에서는 시스템에서 정상적으로 제공하던 기능이 어떤 배포 시점을 기준으로 제대로 동작하지 않게 되는 상황을 지칭한다.
◦
즉, 기능 개발이 제대로 되어있지 않던 과거로 회귀했다는 의미로 따라서 Regression은 버그의 일종이며 이때문에 Regression Bug라고 부르는 편이 조금 더 정확하다.
•
이런 회귀 버그 문제는 테스트를 꼼꼼히 수행함으로써 방지할 수 있으며 이런 목적으로 만들어진 테스트를 회귀 테스트라고 한다.
•
대부분의 사람들은 새로운 팀에 합류해서 기여를 하고자할 때, 내 기여가 문제가 되진 않을까라는 고민을 한 번씩 해본적 있을 것이다.
◦
이는 대부분의 프로젝트가 성장하면서 암묵적인 약속이나 맥락이 생겨나는 경우가 존재하기 때문으로 프로젝트와 관련이 없던 사람은 이러한 맥락을 모른 채 개발하기 때문이다.
•
때문에 이런 두려움을 이겨내고 확신을 가져다 줄 수 있는 방법이 시스템적으로 필요한데, 이것이 바로 자동화된 회귀 테스트이다.
•
회귀 테스트도 중요하지만 더 중요한 것은 그 회귀 테스트가 자동적으로 이뤄져야 한다는 것이다. 회귀 테스트를 사람이 직접하는 것은 비효율적이기 때문이다.
•
자동화된 회귀 테스트를 프로젝트를 확장하고 유지보수하는 과정에서 적극적으로 활용하자. 기능을 개발, 수정하고 단순히 회귀 테스트를 실행시켜보면 되기 때문이다.
2. 의도
•
수정된 공통 코드가 처음 만들어졌을 때의 개발 의도를 벗어나게 되는 경우, 의존성을 가진 클래스들이 영향을 받게 된다고 했다.
•
나아가 이런 문제를 배포 전에 확인할 수 있게 만들어진 것이 회귀 테스트라는 이야기도 했다.
•
그렇다면 우리는 타인이 작성한 코드에서 의도를 어떻게 이해할 수 있을까?
◦
가장 확실한 방법은 코드 작성자에게 가서 직접 물어보는 방법일 것이다. 이 방법은 원초적이면서도 가장 확실하지만 내가 제어할 수 있는 방법이 아니다.
◦
물론 코드를 읽으며 의도를 파악하는 것도 충분히 가능하다. 하지만 코드를 읽는 것만으로 부족한 경우가 있다.
•
테스트가 개발자의 의도를 확인하기에 최고의 방법이라고 저자는 말한다.
•
테스트를 이용하면 클래스에 할당된 책임과 의도를 테스트에 기술할 수 있다. 즉 어떤 객체의 책임과 의도를 테스트에 풀어내는 과정에서 객체에 할당된 책임을 다시 확인할 수 있기 때문이다.
•
우리가 작성하는 테스트는 주로 클라이언트의 관점에서 객체가 책임을 제대로 수행하고 있는가에만 관심이 있다. 객체에게 고정된 입력을 주고 원하는 출력이 나오는지만 확인한다. 내부 구현은 전혀 신경쓰지 않기 때문이다.
•
따라서 테스트를 의도를 드러내는 수단으로 바라보는 것이 가능하며 더 나아가 책임을 드러내는 수단으로 활용할 수 있게 된다면 객체지향의 방법론인 책임 주도 설계에 가까워질 수 있다.
•
더 나아가 테스트는 그 자체로 문서가 될 수 있다. 테스트는 개발자의 의도를 보여주는 수단이며 계약의 내용을 가장 구체적이고 상세히 설명할 수 있는 수단이다. 누구나 클래스에 할당된 책임이 무엇인지 테스트를 통해 확인할 수 있다.
3. 레거시 코드
•
소프트웨어 분야에서 레거시 코드라는 단어를 흔하게 접해봤을 것이다.
◦
이는 보통 현재의 기술 트렌드나 모범 사례와 동떨어진 코드를 지칭하는데 사용되곤 하며 이와 같은 의견에 대부분의 개발자들은 동의할 것이다.
•
레거시 코드 활용 전략이라는 책을 쓴 마이클 페더스는 레거시 코드를 테스트 루틴이 없는 코드라고 말했다. 즉 그의 정의에 따르면 작성된 시기에 상관없이 테스트 코드가 없는 코드는 레거시 코드가 되는 것이다.
•
이 정의는 굉장히 명쾌하면서도 레거시 코드가 가지고 있는 본질적인 문제점을 강조한다.
•
일반적으로 오래된 코드가 레거시 코드로 여겨지는 이유는 그 코드를 이해, 변경하기 어렵다는 점 때문으로 이 문제는 테스트 코드를 통해 해결될 수 있다.
◦
테스트 루틴이 충분히 갖춰진 코드는 오래됐더라도 안정적이고 변경에 대응하기 쉽다.
•
이런 사실에 기인해서 리팩토링의 저자 마틴 파울러는 리팩토링을 하기 위해선 반드시 테스트가 동반되어야 한다고 말한다. 그리고 코드를 변경한 결과로 입력에 따른 출력이 달라진다면 이는 리팩토링이 아닌 기능을 변경한 것이라고 한다.