////
Search
Duplicate
🏒

Chapter 13. 테스트 피라미드

테스트를 분류하는 가장 일반적이고 대중적인 분류 체계로 이 체계에서는 테스트를 단위 테스트, 통합 테스트, E2E 테스트의 3단 피라미드 형태로 분류한다.
테스트 피라미드의 y축은 테스트가 실제 사용자의 사용 사례와 얼마나 가까운지를 나타내는데, 위쪽에 위치할수록 아래에 있는 테스트보다 실제 환경에 가까운 테스트라고 볼 수 있다.
테스트 피라미드의 각 계층에 대한 일반적인 설명은 다음과 같다.
1.
단위 테스트
단위 테스트는 소프트웨어를 구성하는 가장 작은 단위를 검증하는 테스트를 의미한다.
여기서 말하는 Unit이란 통상적으로 함수, 메소드, 클래스 같은 개별적이고 작은 코드 조각을 지칭한다.
따라서 단위 테스트란 객체나 컴포넌트에 할당된 작은 책임이 예상대로 동작하는지 확인하는 테스트라고 볼 수 있다.
2.
통합 테스트
통합 테스트는 여러 컴포넌트나 객체가 협력하는 상황을 검증하는 테스트를 말한다.
즉, 통합 테스트는 독립적으로 만들었던 객체들이 상호작용하면서 생길 수 있는 상황을 검증한다.
객체지향 관점에서 본다면 객체들의 협력이 제대로 이뤄지는지 평가하는 단계다.
어플리케이션 서비스 관점에서 본다면 비즈니스 프로세스의 흐름을 검사하는 단계다.
통합 테스트를 조금 더 추상화시키면 서로 다른 모듈이나 시스템 간의 인터페이스를 테스트하는 것이라 볼 수도 있다.
이때문에 통합 테스트는 연동 시스템의 장애나 예외 상황이 발생했을 때, 시스템이 어떻게 대처하는지 테스트하는 역할을 하기도 한다.
3.
E2E 테스트
실제 사용자 시나리오에서 시스템이 어떻게 동작하는지를 검증하는 테스트를 말한다.
백엔드 개발자 입장에서 종종 API 테스트라고 부르기도 하는데, 백엔드 ㅅ버를 실행하고 해당 서버에 필요한 하위 컴포넌트를 모두 구동시킨 후 API를 호출하는 방식으로 테스트를 작성하기 때문이다.
이처럼 테스트를 어떤 식으로 분류하는 지도 설명하지만 각 분류가 시스템에 얼마나 분포해야 하는지도 직관적으로 설명한다.
단위 테스트가 가장 많고, 그 다음이 통합, E2E 순으로 말이다. 이상적으로는 각각 80%, 15%, 5%가 좋다고 한다.
더불어 테스트를 작성해야할 때, 우선순위에 대한 힌트도 얻을 수 있다. 피라미드를 만들 때 가장 아래부터 만드는 것처럼 단위 테스트부터 차례대로 만들어야 함을 나타낸다.
이렇기 때문에 가장 많이 작성하고 가장 먼저 작성되는 단위 테스트가 제일 중요하다고 할 수 있다.
저자는 이런 전통적인 테스트 피라미드에 대한 불만을 가지고 있기 때문에 이보다 더 낫다고 생각하는 구글의 테스트 피라미드를 소개한다.
그 정의가 모호하기 때문이다. 단위 테스트에서 의미하는 그 단위란 무엇인가?
어디까지 통합되어야 통합 테스트의 범주에 들어가는 것일까?

1. 구글의 테스트 피라미드

구글의 테스트 피라미드는 소형 - 중형 - 대형으로 이뤄졌다.
인지 모델 자체는 명칭만 달라 보인다. 구글은 단위니 통합이니 그런 단어들을 사용하는 대신 대형, 중형 테스트라는 용어를 사용한다.
이는 테스트의 크기에 따라 테스트를 분류하는 것인데, 여기서 말하는 테스트의 크기란 테스트를 실행하기 위해 사용하는 자원의 크기를 말한다.
1.
소형 테스트 : 단일 서버, 단일 프로세스, 단일 스레드에서 동작하며 디스크 입출력, 블로킹 호출이 없는 테스트를 의미한다.
2.
중형 테스트 : 단일 서버에서 동작하되 멀티 프로세스, 멀티 스레드를 사용할 수 있는 테스트를 말한다.
3.
대형 테스트 : 멀티 서버에서 동작하는 테스트를 말한다.
표로 표현하면 다음과 같다.
멀티 스레드
멀티 프로세스
멀티 서버
소형 테스트
X
X
X
중형 테스트
O
O
X
대형 테스트
O
O
O
구글은 왜 테스트를 실행하는 데 사용되는 자원의 크기를 기준으로 이런 분류 체계를 만들게 되었을까?

2. 테스트 분류 기준

새로운 테스트 분류 체계에 사용할 테스트 분류 기준은 무엇이 되면 좋을까?라는 질문에 구글은 다음과 같이 대답했다.
1.
테스트가 결정적인가?
2.
테스트의 속도가 빠른가?
구글이 생각하는 테스트를 구분 짓는 주요 특징은 위 두 가지다. 바로 테스트의 결정성과 속도다. 일반적으로 이 두 조건을 만족시키는 테스트가 좋은 테스트라고 불리기 때문이다.
테스트가 결정적이라는 건 무슨 의미일까? 일관된이라는 표현으로 이해해도 괜찮다. 즉, 같은 코드를 대상으로 실행하는 테스트는 항상 같은 결과를 내야 한다는 의미다.
매번 실행 시 결과가 달라지는 테스트를 비결정적인 테스트라고 하며 생각보다 우리 주변에서 자주 찾아볼 수 있다.
그렇다면 좋지 않은 테스트는 어떨 때 만들어지는 것일까?
먼저 테스트가 비결정적으로 동작하게 되는 경우는 다음과 같다.
테스트가 병렬 처리를 사용할 경우
테스트가 디스크 입출력을 할 경우
테스트가 다른 프로세스와 통신할 경우
테스트가 외부 서버와 통신할 경우
속도가 느려지는 경우는 다음과 같다.
테스트가 블로킹 호출을 사용할 경우
테스트가 디스크 입출력을 사용하는 경우
테스트가 다른 프로세스와 통신할 경우
테스트가 외부 서버와 통신할 경우
즉, 테스트는 블로킹 호출, 디스크 입출력 등이 있을 때 느려지고 비결정적으로 동작하는데, 즉 테스트가 점유하는 자원의 양이나 종류에 따라 테스트의 형태가 결정된다.
소형 테스트의 표면적인 목표는 테스트를 단일 서버, 단일 프로세스, 단일 스레드로 만드는 만드는 것이라 볼 수 있지만 실질적이 목표는 테스트를 결정적이고 빠르게 만드는 것이다.
중형 테스트는 좀 더 완화된 기준을 가지나 멀티 서버를 금지하기 때문에 여전히 네트워크 호출은 금지한다.
대형 테스트의 경우, 모든 테스트를 로컬에서만 처리할 수 없기 때문에 서버를 여러대 띄워야하는 경우 사용한다.
각 테스트의 분류를 리소스가 아닌 의미론적 기준으로 분류한다면 다음과 같이 분류할 수도 있다.
결정적인가?
빠른가?
소형
O
O
중형
X
대형
X
X

3. 소형 테스트의 중요성

이번 장을 마무리하면서 반드시 기억해야할 인사이트는 다음과 같다.
시스템에는 소형 테스트가 많아야 한다.
중형 테스트나 대형 테스트가 소형 테스트보다 많아지는 것은 바람직하지 않은 현상이다.
소혀 테스트는 단일 스레드, 단일 프로세스, 단일 서버에서 실행되며 디스크 입출력, 블로킹 호출이 없는 테스트다.
H2를 이용하는 테스트는 중형 테스트이다.
저자는 소형 테스트를 다시 한번 강조한다.
소형 테스트를 작성하기 위해 책임을 분배하다보면 트랜잭션 스크립트같은 코드가 나올 확률이 줄어 든다.
마지막으로 소형, 중형, 대형 테스트는 어떤 컴포넌트를 테스트하느냐에 따라 분류되지 않음을 기억하자.