RTL은 라이브러리지만 완고한 형식으로 라이브러리 작성 방식이 특정환 관행을 권장한다
테스트 라이브러리의 또 다른 완고한 부분은 접근성 마커로 요소를 찾는 것
즉, 테스트 ID를 사용하는 대신 스크린 리더와 다른 보조 기술로 요소를 찾는 것이다
RTL은 테스트를 위한 가상 DOM을 제공한다
브라우저 없이 테스트를 진행하면 클릭 요소와 같은 작엄을 할 때 가상 DOM이 필요로 하다
그리고 가상 DOM이 원하는 대로 작동하는지 확인할 수도 있다
반면, Jest는 테스트 러너이다
그래서 테스트를 찾고 실행하는 것과 테스트 통과 여부를 결정하는 역할을 한다
버튼등을 가지고 테스트 라이브러리를 사용해 볼건데 일단 CRA
(create-react-app)을 통해 프로젝트를 하나 만들고 시작해보자
이후 npm test
를 입력해보자. npm test는 Jest에서 Watch 모드 실행으로 시작된다
Watch 모드와 테스트를 실행하면 여러 글자가 뜨는데
이런 글이 뜬다.
우선은 a를 입력해서 테스트를 실행시켜보자
테스트를 실행하며 한개의 테스트를 찾고 통과했다고 뜰것이다
근데 나는 아무것도 작성한게 없는데요? 기본적으로 CRA로 테스트를 만들었을 때 함께 제공되는 테스트로 App.test.js
라는 파일에 있다
먼저 q를 입력하여 Watch모드를 종료하고 코드에디터로 살펴보면
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
이런 테스트 코드를 볼 수 있다
한줄 씩 살펴보자
render
메서드를 실행한다render
메서드는 인수로 제공하는 JSX에 관한 가상 DOM을 생성한다screen global
객체를 통해 액세스 한다render
와 screen global
도 RTL에서 임포트해서 가져온다getByText
라는 screen
객체에서 메서드를 실행하며 표시되는 모든 텍스트를 기반으로 DOM에서 요소를 찾는다getByText
옆에 작성된 인수 /learn react/i
는 정규표현식으로 "learn react"라는 문자열이고 대소문자는 구분하지 않는다(i) 라는 뜻이다Learn React
App.js
를 살펴보면 해당 문자열 요소를 찾을 수 있다만약 getByText
인수의 정규식을 App.js
에서 찾아볼 수 없는 문자열등으로 변경하면 어떻게 될까?
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react testing library/i);
expect(linkElement).toBeInTheDocument();
});
테스트는 실패해야 하고 문서에서도 볼 수 없어야 한다
당연히 실패했다는 에러를 받았다. /learn react testing library/i
요소를 찾을 수 없다는 내용이다
expect(linkElement).toBeInTheDocument();
위에서 말한 것처럼 단언은 테스트의 통과 여부를 결정한다
먼저 해당 코드를 하나씩 보자면
expect(linkElement)
: Jest에서 전역 메서드인 expect 메서드toBeInTheDocument
: 일종의 매처(Matcher)를 사용하는데 이것이 단언의 유형이다toBeInTheDocument
toBeInTheDocument
는 인수가 없다-> 요소가 문서에 있거나 없는 것예시를 몇가지 봐보자
expect(element.textContent).toBe('hello');
시작은 언제나 expect
로 시작하고 대상은 element.textContent
이다
요소는 위에 봤던 코드처럼 미리 정의했다고 가정한 뒤 textContent
는 요소의 텍스트 콘텐츠이다
그리고 매처는 toBe
이다. 대상이 무엇이든 인수를 'hello'라는 매처에 일치시켜야 한다
텍스트 콘텐츠 요소를 'hello'로 예상하는 것
expect(elementsArray).toHaveLength(7);
마찬가지로 elementsArray
는 미리 정의했다고 하고 toHaveLength
라는 매처를 사용했다
인수는 7
로 배열 요소의 길이를 7로 예상하는 것이다
CRA와 함께 제공되며 함께 설치된다. setupTests.js
파일을 사용해 각 테스트 전에 jest-dom을 가져오기 한다
즉, 모든 테스트에서 jest-dom 매처를 사용할 수 있는 것
위 App.test.js
코드에서 toBeInTheDocument
라는 매처를 사용했었는데 DOM을 기반으로 한 매처이며 방금 살펴본 예시에서 사용한 toBe
,toHaveLength
는 일반적인 매처이다
toBeInTheDocument
와 같은 DOM기반의 매처는 가상 DOM에만 적용할 수 있다
다른 매처로는 DOM에서 볼 수 있는 toBeVisible()
과 체크박스와 같은 toBeChecked()
가 있고 훨씬 더 많다
2개의 인수를가진 전역 테스트 메서드가 있다
App.test.js
파일의 test
함수의 함수 인수 내용을 전부 지우고 빈 테스트를 시작해도 통과된다코드 작성 전에 테스트를 작성하고 테스트에 통과하도록 코드를 작성하는 것
보통 레드-그린 테스트라고 부르는데 코드 작성 전에 테스트에 실패하는 레드 테스트를 먼저 실행하고 코드 작성 후에는 통과하는 테스트로 그린 테스트를 확인하는 것이다
그래서 보통 테스트를 작성하기 전에 약간의 코드를 작성해서 테스트에 오류가 발생하지 않도록 한다
따라서 테스트에 실패하면 빨간색이 표시되고 통과하면 초록색이 표시된다
일단 RTL은 테스트를 위한 가상 DOM을 생성하고 DOM과 상호 작용하기 위한 유틸리티도 제공한다
예시로
유닛테스트
보통 함수나 별개의 React 컴포넌트 코드의 한 유닛 혹은 단위를 테스트하는 것으로
이 유닛이 다른 코드의 유닛과 상호 작용하는 것을 테스트하진 않는다
통합 테스트
통합 테스트는 여러 유닛이 함께 작동하는 방식을 테스트해서 유닛 간의 상호 작용을 테스트 하는 것
예를 들면 컴포넌트 간의 상호작용을 테스트하거나 마이크로 서비스 간의 상호 작용을 테스트한다
기능 테스트
소프트웨어의 특정 기능을 테스트하는 것
헷갈릴 수 있는 게 function은 영어로 함수에서 입력값을 취하고 출력값을 제공하는 소프트웨어 단위(Unit)을 의미할 수 있고 동작을 의미할 수도 있는데 이 경우 동작과 관련한 의미에 해당한다
특정 코드 함수가 아닌 소프트웨어의 일반적인 동작을 의미한다
일반적인 동작이라는게 뭔데? 한다면 데이터를 폼에 입력하고 제출을 클릭하면 소프트웨어가 특정 데이터 세트로 바르게 작동하는 기능을 확인해야 한다
여러 유닛이 있는 통합 테스트 일수도 있지만 유닛테스트인 기능 테스트 일 수도 있다
입력란에 잘못된 데이터를 입력하면 에러가 나는지 보는 테스트 일수도 있는 것
유닛 테스트에 가까울 뿐 기능 테스트이다
개념은 코드가 아닌 동작을 테스트 하는 것!이다
인수 테스트 or End to End테스트
종종 E2E 테스트라고도 하는데 이 테스트는 실제 브라우저가 필요하고 애플리케이션이 연결된 서버가 필요하다
보통 Cypress나 Selenium과 같은 특별한 도구가 필요함