최근에 읽은 책인 '로버트 마틴'의 '클린 코더'라는 책에 테스트에 관련한 좋은 내용이 있어서 정리해둔다.
⭐️ 인수 테스트
인수(acceptance) 테스트는 요구사항이 언제 완료되는지를 정의하기 위해 이해당사자들과 프로그래머들이 힘을 모아 작성하는 테스트라고 정의한다.
- 인수 테스트의 목적은 소통, 명확성 및 정밀성이다.
- 개발자, 이해당사자 및 테스터 모두 동의함으로써 시스템 행동을 위한 계획을 이해하며, 모든 당사자들이 이런 명확성 획득에 책임이 있다.
- 인수 테스트는 언제나 자동화해야 한다. 그 이유는 단순하다. 비용 때문이다.
- 수작업 테스트는 스크립트를 사람이 실행하기 때문에 경제적 타당성이 전혀 없는데 반해, 자동화한 인수 테스트는 비용이 매우 저렴하다.
- 인수 테스트 자동화를 쉽게 만들어주는 오픈소스와 상업용 도구로 FitNesse, Cucumber, cuke4duke, robot framework, Selenium 등이 있다.
- 기능 구현 작업은 그 기능의 인수 테스트가 준비되면 시작한다. 개발자는 새 기능에 대한 인수 테스트를 실행해서 오류 과정을 살핀다.
⛓ 인수 테스트 vs 단위 테스트
- 인수 테스트는 단위 테스트가 아니다. 단위 테스트는 프로그래머가 프로그래머를 위해 만든다. 단위 테스트는 프로그래머가 프로그래머들을 위해 만든다.
- 단위 테스트는 코드의 최하위 구조와 행동을 설명하는 공식 디자인 문서다. 단위 테스트를 읽는 사람은 사업부가 아니라 프로그래머다.
- 인수 테스트는 사업부가 사업부를 위해 작성한다. 인수 테스트는 사업적 관점에서 시스템이 어떻게 운영되어야 하는지를 구체적으로 표시한 공식 요구사항 문서다. 보는 사람은 사업부와 프로그래머다.
- 단위 테스트와 인수 테스트는 첫째가 문서고 둘째가 테스트다. 테스트의 주 목적은 시스템의 디자인, 구조 및 행동의 공식적인 문서화다.
- 테스트가 자동으로 명세하는 디자인, 구조 및 행동을 검증한다는 사실도 쓸모 있지만, 테스트의 진정한 목적은 사양의 명세다.
🕰 테스트 전략
저자는 프로 개발팀에게는 훌륭한 테스트 전략이 필요하다고 말하고 있다. 그리고 동시에, QA는 오류를 찾지 못해야 하며 QA와 개발자는 적이 아니라고 말한다.
인수테스트는 시스템에 대한 진정한 명세서이자 요구사항 문서다. ... 보통 사업부는 행복한 경로(happy-path)의 테스트를 만들고 QA는 모퉁이 조건, 경계 조건, 불행한 경로(unhappy-path)의 테스트를 만든다.
🔗 테스트 자동화 피라미드
프로 개발팀은 인수 테스트로 시스템을 명세화하고 지속적 통합으로 고친 오류가 다시 생기지 않도록 한다. 하지만 이런 테스트는 전체의 일부분이다. 단위 테스트와 인수 테스트 묶음(suite)은 쓸모가 많지만, 오류가 발생하지 않으리라는 확신을 가지려면 상위 계층 테스트 또한 필요하다.
테스트 자동화 피라미드의 테스트를 각각 위에서부터 순서대로 나열하자면 다음과 같다.
- 탐색 테스트(Exploratory tests)
- 시스템 테스트(System tests)
- 통합 테스트(Integration tests)
- 컴포넌트 테스트(Component tests)
- 단위 테스트(Unit tests)
💡 단위 테스트
- 단위 테스트는 프로그래머에 의해, 프로그래머를 위해 시스템 프로그래밍 언어로 만든 테스트다.
- 단위 테스트는 시스템의 최하위 계층을 명세하려는 의도로 만든다.
- 단위 테스트의 커버리지는 최대한 100%에 가까워야 한다. 보통 커버리지의 목표는 90 ~ 99% 사이가 되어야 한다.
🔌 컴포넌트 테스트
- 컴포넌트 테스트는 인수 테스트의 일종이다.
- 컴포넌트 테스트의 대상은 시스템의 독립 컴포넌트다.
- 시스템의 컴포넌트는 업무 규칙을 감싸고 있기 때문에, 컴포넌트를 대상으로 한 테스트는 해당 업무 규칙을 테스트하는 인수 테스트다.
- 컴포넌트 인수 테스트는 컴포넌트를 감싸고 있다. 컴포넌트 입력 데이터를 넣고 출력 값을 받아 모으고, 입력 값에 대해 출력 값이 올바른지 테스트한다.
- 테스트 대상이 아닌 다른 시스템 컴포넌트는 적절한 모의(mock) 컴포넌트와 테스트 대역(test-doubling) 기법으로 테스트로부터 분리한다.
- 컴포넌트 테스트는 대략 시스템의 절반 정도를 감당한다. 행복한 경로(happy-path)쪽에 치우쳐 있으며 모퉁이 조건, 경계 조건, 대체 경로(alternate-path)는 아주 명백한 경우만 처리한다.
- 불행한 경로(unhappy-path)는 대부분 단위 테스트로 처리하며 컴포넌트 테스트에서는 의미가 없다.
⚖️ 통합 테스트
- 통합(Integration) 테스트는 여러 컴포넌트로 이뤄진 큰 시스템에서만 의미가 있다.
- 컴포넌트 묶음을 모아 묶음끼리 제대로 상호작용하는지 테스트한다.
- 테스트 대상이 아닌 시스템의 다른 컴포넌트는 보통 적절한 모의(mock) 컴포넌트와 테스트 대역(test-double)으로 테스트와 분리한다.
- 통합 테스트는 안무(choreography) 테스트다. 업무 규칙은 테스트하지 않고 조립한 컴포넌트 묶음끼리 얼마나 잘 어우러져 춤을 추는지 테스트한다.
- 통합 테스트는 배관(plumbing) 테스트다. 컴포넌트끼리 서로 적절히 연결되어 또렷이 소통하는지 테스트하기 때문이다.
- 통합 테스트는 시스템 구조 설계가 튼튼하다는 사실을 보장한다. 성능 테스트나 처리량(throughput) 테스트를 하기도 하는 단계다.
- 통합 테스트는 대개 컴포넌트 테스트에 썼던 언어와 환경으로 만들며, 통합 테스트는 실행에 시간이 많이 들기 때문에 보통 지속적 통합(일명 CI) 때는 돌리지 않는다. 대신 주기적으로 만든 이가 필요할 때마다 테스트를 돌린다.
⚙️ 시스템 테스트
- 시스템 테스트는 통합한 시스템 전체를 대상으로 하는 자동화 테스트다. 즉, 궁극적인 통합 테스트다.
- 직접적으로 업무 규칙을 테스트하지 않으며, 시스템이 올바르게 연결됐고 각 부분이 계획에 따라 상호작용하는지 테스트한다. 보통 성능이나 처리량 테스트는 이 단계에서 한다.
- 시스템 테스트는 대략 시스템의 10%를 감당한다. 시스템이 올바로 동작하는지보다 시스템을 올바르게 빌드했는지를 확실히 하려는 목적이기 때문이다(기반 소스코드와 컴포넌트가 제대로 동작하는지는 피라미드의 하위 계층에서 이미 확인했다).
🔦 수동 탐색 테스트
- 수동 탐색 테스트는 키보드에 손을 얹고 모니터를 직접 보며 하는 테스트다. 자동화된 테스트가 아니며 스크립트로 작성된 테스트도 아니다.
- 이 테스트의 목적은 시스템이 기대한 대로 동작하는지 확인하는 동시에 예상치 못한 오류를 찾아내는 것이다.
- 목표 달성에는 인간의 두뇌와 창의력으로 시스템을 검사하고 탐색하는 과정이 필요하다.
- 목표는 커버리지가 아니다. 모든 업무 규칙과 실행 경로를 빠짐없이 검사하는 것이 아닌, 사용자의 조작에 시스템이 잘 동작하는지 확인하고 가능한 많은 '특이사항'을 창의적으로 발견해내는 일이 목표다.
참고자료