# 테스트 범위

### 테스트 범위

> 웹 애플리케이션은 여러 모듈을 조합해 만든다.

* 한 가지 기능을 구현할 때 구성되는 모듈들
  * 1.라이브러리가 제공하는 함수
  * 2.로직을 담당하는 함수
  * 3.UI 관련 함수
  * 4.웹 API 클라이언트
  * 5.API 서버
  * 6.데이터베이스 서버
* <mark style="color:red;">테스트를 작성할 때는 어디부터 어디까지 커버하는 테스트인지 주의해야 한다.</mark>
* 테스트 범위는 크게 네가지로 분류된다.

#### 정적 분석

* 타입스크립트나 ESLint가 제공하는 기능을 활용
* 각 모듈 내부의 검증뿐만아니라 **(2.로직을 담당하는 함수 \~ 3.UI 관련함수 검증)**, **(3.UI 관련함수 검증 \~** **4.웹 API 클라이언트**) 검증처럼 인접 모듈을 연계해 사용할 때의 문제점도 검증한다.

#### 단위 테스트

* 한 가지 모듈에 한정하여 해당 모듈이 제공하는 기능을 검증하는 가장 기초적인 테스트
* 독립된 환경에서 검증하기 때문에 실제 애플리케이션을 사용할 때는 거의 발생하지 않는 케이스\*(코너 케이스)검증에 적합
  * 코너케이스에 한해서만 예외를 발생시키는 것이 나은 경우도 있다.
  * 어떤 상황에서 예외를 발생시켜야 할지 판단할 때 도움이 된다.
  * <mark style="color:blue;">'이런 상황은 일어날 수 없을까? 일어날 수 있다면 어떻게 처리해야 하는가'와 같은 거듭된 검토 과정에서 미처 고려하지 못했던 부분을 발견할 수 있다.</mark>
  * <mark style="color:blue;">**ex: 다른 입력 패턴은 없나?, 예외처리는 충분한가..?**</mark>
* 테스트할 모듈이 **특정 입력값을 받아 기대하는 출력값을 반환하는지 테스트**
* UI 컴포넌트는 입력값(props)에 알맞은 출력값(HTML 블록)을 반환하기 때문에 일반적인 함수와 같은 방법으로 테스트할 수 있다.
* 단위 테스트로 함수가 고려하지 못한 부분이 없는지 검증

#### 통합 테스트

* **여러 모듈을 연동한 기능을 테스트**
* 1.라이브러리가 제공하는 함수 \~ 4.웹 API 클라이언트, 2.로직을 담당하는 함수 \~ 3.UI 관련 함수 처럼 **모듈 조합으로 제공되는 기능을 검증하는 테스트**&#x20;
* 범위가 넓어질수록 효율적인 테스트가 가능하지만 **상대적으로 대략적인 검증에 그치게 된다.**
* 커다란 UI 컴포넌트는 여러 모듈을 조합해 기능을 제공하며, 기능은 주로 인터렉션에서 시작된다.
  * 셀렉트 박스 조작 \*(인터렉션)
  * URL 검색 쿼리 변경됨
  * 검색 쿼리가 변경되어 데이터 취득 API 호출됨
  * 목록 화면 내용 갱신
  * **즉, 셀렉트 박스 조작을 실행하면 목록 화면 내용도 갱신된다.를 테스트 하는 것**
* 코너 케이스 때문에 테스트가 복잡해지면 범위를 좁혀서 통합 테스트를 실시해야 테스트 목적이 명확해진다.

#### **E2E 테스트**

* **UI 테스트 뿐만 아니라 외부 스토리지와 같이 연동 중인 하위 시스템을 포함하는 테스트**
* 1.라이브러리가 제공하는 함수 \~ 4.웹 API 클라이언트 검증을 통틀어 헤드리스 브라우저와 UI 자동화 도구를 결합하여 검증하는 테스트
* 가장 광범위한 통합 테스트
* 실제로 애플리케이션을 사용할 때와 가장 유사한 테스트
* 입력 내용에 따라 저장된 값이 갱신되기 때문에 UI는 물론 연동된 외부 기능이 정상적으로 작동하는지 검증할 수 있다.

### 테스트 목적

* 테스트 타입은 테스트 목적에 따라 분류됨
* 테스트 분야에서 많이 알려진 테스트 타입은 **기능 테스트**, **비기능 테스트**, **화이트 박스 테스트, 회귀 테스트** 등이 있다.
* 테스트 타입은 검증 목적에 맞게 설정해야 하며, 테스트 타입마다 적절한 테스트 도구가 있다.

#### 기능 테스트 (인터렉션 테스트)

* **개발된 기능에 문제가 없는지 검증하는 테스트**
* 웹 프론트엔드의 대부분 기능은 UI 컴포넌트 조각(인터렉션)에서 시작되기 때문에 주로 인터렉션 테스트가 기능 테스트가 될 때가 많고 중요하다.
  * 웹 프런트는 사용자가 조작할 UI 컴포넌트를 개발하기 때문에 인터렉션 테스트가 대부분
* 실제 브라우저 API를 사용하는 것이 중요한 테스트라면 헤드리스 브라우저와 UI 자동화 도구를 사용하는 것이 좋음
* UI 컴포넌트에는 브라우저 없이도 테스트할 수 있는 가상 브라우저 환경이 있음

{% hint style="info" %}
실제 브라우저가 없어도 가능한 인터렉션 테스트 사례

* 버튼을 클릭하면 콜백 함수 호출됨
* 문자를 입력하면 전송 버튼이 활성화됨
* 로그아웃 버튼을 클릭하면 로그인 화면으로 이동함

\*But 가상 브라우저만으로는 스크롤이나 세션 스토리지같은 기능은 테스트할 수 없다. 실제 브라우저가 없으면 수행하기 어려운 기능의 테스트는 헤드리스 브라우저와 UI 자동화 도구를 사용한다.

실제 브라우저가 필요한 인터렉션 테스트 사례

* 맨 아래까지 스크롤을 내리면 추가 데이터를 가져온다.
* 세션 스토리지에 저장된 값을 불러온다.
  {% endhint %}

#### 비기능 테스트(접근성 테스트)

* 접근성 테스트는 비기능 테스트의 한 종류
* 신체적, 정신적 **차별없이 동등하게 제품을 사용할 수 있는지 검증**하는 테스트
* 최근 전 세계적으로 웹 접근성 관련 API가 여러 플랫폼에 추가되어 테스트 자동화를 할 때 객관적으로 검증할 수 있는 환경이 갖추어짐
* 마찬가지로 접근성 테스트는 기능 테스트와 동일하게 가상 브라우저와 실제 브라우저를 사용하여 테스트 진행
  * 같은 도구를 사용하면 기능 테스트의 초보자가 접근성 품질을 높이는 출발점으로 삼는데 도움됨

{% hint style="info" %}
접근성 테스트 실제 사례

* (키보드로) 체크 박스를 체크할 수 있다.
* 오류 응답을 받았을 때 오류 문구를 렌더링한다.
* 렌더링된 화면에 접근성 위반사례가 있는지 검사한다.
  {% endhint %}

#### (시각적) 회귀 테스트

* 특정 시점을 기준으로 전후 차이를 비교하여 문제가 있는지 검증하는 테스트
* 웹 프론트엔드는 시각적으로 보이는 UI 컴포넌트를 개발하기에 시각적 회귀 테스트가 중요하다.
* CSS(종속형 시트)는 UI 컴포넌트에 정의된 스타일뿐만 아니라 브라우저에 적용된 모든 스타일의 영향을 받는다.
* 회귀 테스트 중 하나인 시각적 회귀 테스트에서는 **헤드리스 브라우저에 그려진 내용을 캡처하여 캡처된 이미지 간 차이를 검증**한다.
  * 초기에 렌더링된 상태만 캡처하여 비교하는 것에 그치지 않고 사용자 조작으로 변경된 화면까지 캡처하여 비교

{% hint style="info" %}
시각적 회귀 테스트 사례

* 버튼 스타일에 차이가 없다.
* 메뉴 바를 열었을 때 화면에 차이가 없다.
* 렌더링된 화면에 차이가 없다.
  {% endhint %}

## 테스트 전략 모델

* 단위테스트 < 통합 테스트 < E2E 테스트
  * 낮은 유사성, 짧은 실행시간, 높은 안정성 <<< 높은 유사성, 긴 실행시간, 낮은 안정성
* 상층부 테스트는 많은 시간과 비용이 발생한다.
  * 테스트용 데이터베이스 서버 구축 및 실제 환경과 최대한 유사한 환경을 구축해야 한다.
  * 테스트할 때마다 제품과 연동된 외부 시스템의 응답도 기다려야 하기에 다른 테스트보다 긴 실행 시간이 걸린다.
* 테스트 계층 간 비용 분배는 테스트 전략을 세울 때 가장 중요한 검토 사항이다.

### 아이스크리미 콘 (역 피라미드)

* **상층부 테스트의 비중이 높은 아이스크림 콘은 안티패턴으로 자주 언급되는 테스트 전략 모델이다.**
* 운용 비용이 높을 뿐만 아니라 **외부 모듈의 의존성 때문에 아주 가끔식 실패하는 불안정한 테스트가 비교적 많다**.
* 만약 모든 테스트가 통과되는데 수십 분이 상이 걸리면 개발 흐름에 나쁜 영향을 주게 되며 더 나은 개발 환경을 만들고자 테스트를 자동화한 것이 오히려 개발 경험을 해치는 상황이 발생한다.
  * 그러나 실행 시간을 줄이려고 실행 빈도를 줄이면 테스트 자동화의 신뢰성은 낮아진다.

### 테스트 피라미드

* **하층부 테스트의 비중이 높을수록 더욱 안정적이고 가성비 높은 테스트가 가능하다는 것이 핵심**
* 하층부는 실행 시간이 짤방 신속성이 높고, 자주실행할 수 있어서 안정성도 높다.
* 프론트엔드 테스트 자동화에도 테스트 피라미드가 우수한 전략이라는 의견이 지배적

### 테스팅 트로피

* 켄트 도즈(Kent C Dodds)가 만든 테스트 전략 모델
* **통합 테스트 비중이 가장 높아야 한다는 것이 핵심**
* 프론트엔드 개발에서 단일 UI 컴포넌트로 구현되는 기능은 거의 없다.
* 테스팅 트로피에는 사용자 조작을 기점으로 한 통합 테스트 비중이 높을수록 더욱 우수한 테스트 전략이라는 의도가 있음
* 테스팅 라이브러리와 제스트를 사용하면 헤드리스 브라우저 없이도 사용자 조작을 재현해 테스트할 수 있어서 실행 속도가 빠르면서도 실제 제품과 유사한 테스트가 가능하다.&#x20;

## 테스트 전략 계획

> 테스트 전략 모델을 참고해 프로젝트에 최적인 전략을 수립하려면 테스트 대상 및 목적에 따른 판단 기준을 정립해야 한다.&#x20;

### 테스트가 없어 리팩터링이 불안한 경우

* 릴리즈된 프로젝트에 테스트 코드가 없으면 리팩터링이 불안할 수 있다.
* 이때는 먼저 릴리즈된 기능을 목록으로 정리해야 한다.
* 정리가 됐다면 변경 전후로 결함이 발생하지 않았는지 검증하는 회귀 테스트를 작성해야 한다.
* 작성된 회귀 테스트가 있다면 자신있게 리팩터링을 시작할 수 있다.
* 웹 API 서버에 대한 의존성이 깔끔하게 분리되지 않았다면 테스트 작성이 어렵다.
  * 이 때 목 서버를 활용하여 통합 테스트를 실시한다.&#x20;
  * 목 서버를 활용하면 구현 코드를 수정하지 않아도 테스트할 수 있어 리팩터링 시작전에 테스트를 작성하고 싶은 개발자에게 유용하다.  \* 특히 릴리즈된 프로젝트에서 효과적
* 통합 테스트가 늘어날수록 안심하고 리팩터링할 수 있는 기능이 많아진다.
* 점진적으로 테스트를 늘리면서 리팩터링을 실시하면 더욱 안정된 테스트 피라미드 모델을 만들 수 있다.

### 반응형으로 제작된 프로젝트

* 반응형 웹은 하나의 HTML에서 다양한 디바이스에 알맞은 화면을 제공한다.
* 반응형 웹은 테스팅 라이브러리만으로는 스타일을 포함한 세밀한 테스트가 어렵다.
* 반응형처럼 디바이스 간 서로 다른 스타일을 제공하는 경우, CSS가 적용된 렌더링 결과를 검증할 브라우저 테스트가 필요함
  * 이런 상황에서 실시하는 테스트가 브라우저를 사용한 시각적 회귀 테스트
* 스토리북은 UI 컴포넌트 단위로 시각적 회귀 테스트가 가능하다.
* 반응형으로 프로젝트를 제작해야 한다면 스토리북을 사용해서 테스트를 작성하는 것이 효율적
  * Storybook -> **reg-suit**를 활용한 시각적 회귀 테스트

### 데이터베이스를 포함한 E2E 테스트가 필요한 경우

* 목서버가 아닌 실제 웹 API 서버를 사용해서 E2E 테스트를 하고싶다면 테스트용 스테이징 환경을 사용해야 한다.
  * 스테이징 환경이란 실제로 배포할 환경에 가까운 형태로 만든 테스트용 환경을 의미
* E2E 테스트는 테스트 엔지니어가 프로젝트를 릴리즈하기 전에 테스트 계획서를 보면서 수동으로 하는 경우가 많고, 브라우저를 사용한 UI 자동화 방식으로 테스트하는 경우도 있다.&#x20;
  * 브라우저를 사용한 UI 자동화는 아이스크림 콘 모델에 가까운 테스트 전략이 되기 쉽다.&#x20;
  * 명확한 목적을 가지고 더욱 작은 범위의 테스트로도 괜찮은지 먼저 검증해야 한다.

{% hint style="info" %}
스테이징 환경을 만들지 않고 개발자 혼자서 실시할 수있는 테스트 자동화 방법 with 도커 컴포즈

* 테스트할 시스템을 컨테이너화해 CI 환경에서 실행한 후 연동중인 여러 시스템과 함께 테스트 하는것
* 비교적 환경 구축 비용이 적고 개발자 혼자서도 구축할 수 있는 장점이 있다
* 컨테이너를 활용해 테스트하려면 E2E 테스트 프레임워크의 사용법 및 컨테이너 가상화 지식, 연관 시스템 설정 지식이 필요
  {% endhint %}

### 주의사항

* 테스트를 너무 많이 작성하고 있는지 되돌아보기
* 테스트 타입 및 전략은 무수히 많고 여러 종류의 테스트를 작성하다 보면 테스트 범위가 중복되는 것을 발견할 수 있다.
* 스토리북이나 E2E 테스트가 중요한 프로젝트라면 UI 컴포넌트 테스트는 오류 패턴을 검증하는 것으로 충분하다는 결정을 내릴수도 있다.
* 테스트 범위 중복은 테스트를 활발히 작성하는 시기에 발견된다.
* 이전에 기능을 개발하기 위해 작성된 테스트 규모는 새 기능을 개발할 때 어느정도로 테스트를 작성해야 하는지 결정하는 참고 지표로 활용된다.
  * 이 참고 지표는 팀에 일정 규모 이상의 테스트를 작성하도록 유도한다.
* 지나치게 많이 작성한 테스트를 발견했다면 과감하게 줄이자.
* **프로젝트에 알맞은 기술 구성은 무엇이며 어떤 테스트 전략이 프로젝트에 적합한지 항상 되돌아보자.**
