정골라코딩
[React] React 테스팅 본문
1. React 테스팅
-코드 테스트가 필요한 경우
• 코드를 작성하고 나면, 원하는 대로 동작하는지 알기 위해 테스트를 함.
• 코드에 버그가 있으면, 어떤 상황에서 버그가 발생하는지를 알기 위해 테스트를 함.
• 코드를 리팩토링 하면, 원래대로 동작하는지 테스트함.
• 리액트 앱의 컴포넌트가 늘어날수록, 컴포넌트끼리 서로 영향을 미치는 경우가 많아짐.
• 특정 코드가 수정되면, 어떤 컴포넌트에 에러가 발생할 수 있음.
-테스트 코드 작성의 이점
• 언급한 상황들에 대한 테스팅 코드를 작성하여, 미연의 에러를 방지.
• TDD(Test Driven Development) 등의 방법론을 적용하여 생산성을 향상.
• 테스트가 늘어나면서 테스트 코드가 구현 코드에 대한 문서화가 됨.
• 테스트가 용이하게 코드를 작성하여, 코드 품질과 신뢰성을 높임.
-테스터블한 코드 작성하기
• 코드가 영향을 미치는 범위를 최대한 줄인다. 사이드 이펙트를 줄임.
• 하나의 함수가 너무 많은 일을 하지 않게 함.
• 기능들을 작게 분리함.
-End-to-end Testing
• 유저가 어떤 시나리오를 가지고 그 시나리오의 end-to-end로 잘 동작하는지 테스트함.
• 필요한 경우 웹서버, 데이터베이스를 실행함.
• 범위가 너무 넓어서 에러가 발생했을 때 특정 기능이 안 된다는 것은 알 수 있지만, 정확히 어떤 부분에 문제가 생겼는지는 알기 힘듦.
• ex)유저가 회원가입 후,로그인하여 유저 정보 페이지를 볼 수 있는지 테스트하는 경우.
-주요 테스팅 용어
• Mocking - 특정 동작을 흉내 내는 것. ex) 실제 API를 호출하는 게 아니라, 가짜 payload를 반환하는 mocking function을 만듦.
• Stubbing - 더미를 채워 넣는 것. ex) Child 컴포넌트를 렌더링하지 않고, 대신 그 자리에 <div> 등을 채워 넣음.
-테스팅의 구성
• setup - 테스트하기 위한 환경을 만든다. mock data, mock function 등을 준비함.
• expectation – 원하는 테스트 결과를 만들기 위한 코드를 작성함.
• assertion – 정말 원하는 결과가 나왔는지를 검증함.
-React 화이트박스 테스팅, 블랙박스 테스팅
• 화이트박스 테스팅은 컴포넌트 내부 구조를 미리 안다고 가정하고 테스트 코드를 작성.
• 블랙박스 테스팅은 컴포넌트 내부 구조를 모른 채 어떻게 동작하는지에 대한 테스트 코드를 작성.
-테스팅의 범위에 따른 분류
• Unit 테스팅
• Integration 테스팅
• end-to-end(e2e) 테스팅
-Unit Testing
• 다른 부분과 분리된 작은 코드를 만들고 그것을 테스트함.
• 작은 코드는 function, module, class 등을 의미.
• 각 부분이 원하는 대로 동작함을 보장하기 위함.
• 테스트는 서로 분리되어야 함. ex) 특정 컴포넌트가 데이터에 따라 잘 렌더링되는지를 테스트하는 경우.
-Integration Testing
• 앱의 특정 부분이 동작하는지 테스트함.
• ex) 여러 컴포넌트가 한꺼번에 동작하거나, 어떤 페이지의 부분이 잘 동작하는지를 테스트하는 경우.
• ex) react-router, redux 등이 특정 컴포넌트와 함께 잘 동작하는지를 테스트하는 경우.
2. jest
• facebook에서 오픈소스화한 테스팅 프레임워크.
• assertion 함수들, test runner, mock 라이브러리 등을 모두 제공.
• create-react-app에서 기본적으로 사용됨.
• 사용성이 좋고, 가장 인기 있는 프로젝트.
-jest 의 핵심 기능들
• assertion matchers
• async assertion
• mock functions
• testing lifecycle functions
• grouping
• snapshot testing
-assertion matchers
• jest는 풍부한 matcher를 제공하여, 여러 상황에서 match를 체크함.
• expect()는 expectation object를 리턴한다. 이 object의 메서드를 이용해 여러 매칭 상황을 assert함.
-Async Assertion
• 비동기 상황의 테스트를 처리 할 수 있는 여러 방법을 제공함.
• callback, promise, async/await을 모두 활용할 수 있음.
-Mock functions
• mock function을 만듦.
• 모듈 전체를 mocking 함.
• 라이브러리 전체를 mocking 함.
-Lifecycle functions
• 각 테스트의 시작과 끝, 전체 테스트의 시작과 끝에 원하는 작업을 할 수 있음.
• beforeEach, afterEach, beforeAll, afterAll 함수를 활용함.
• describe 블록 안에 사용하면 별도의 scope를 가짐.
-Grouping
• describe 함수를 이용해 여러 test() 함수를 논리적으로 나눔.
• describe 함수 안에 describe 함수가 중첩될 수 있음.
-Snapshot testing
• 특정 함수, 모듈, 컴포넌트 등의 결과를 serializable한 형태의 snapshot으로 저장하고, 추후 변경이 발생했을 때 이전의 snapshot과 새로운 snapshot을 비교하여 변경이 발생했는지를 추측함.
• jest의 주요 기능으로, 코드의 변경이 컴포넌트의 렌더링 결과에 영향을 미치는지를 파악하기에 적합함.
-jest 함수의 실행 순서
• beforeAll, beforeEach, afterEach, afterAll의 순서로 Lifecycle 함수들이 실행됨.
• 다만, describe 블록 안에 있는 before-*, after-* 함수는 해당 블록의 범위 안에서 실행됨.
• describe 함수는 모든 test() 함수 이전에 실행된다. 따라서 test() 함수들은 순차적으로 한꺼번에 실행됨.
-테스팅의 구성
3. jest 활용
-Assertion Matchers 활용
• toBe()
• toEqual()
• toContain()
• toMatch()
• toThrow()
-Assertion Matchers 활용
• callback 패턴의 경우, test()함수가 제공하는 done() 함수를 활용하여 콜백이 끝나고 done()을 호출. 에러가 발생하면 done()의 인자로 에러를 넘김.
• Promise 패턴의 경우 async/await을 활용하거나, Promise를 리턴.

-Mock functions
• jest.fn()을 활용하여, mock function 객체를 만듦.
• mockReturnValueOnce() 등으로 리턴하는 값을 임의로 조작한다. 여러번 호출하면, 순서대로 세팅된 값을 반환함.
• mockResolvedValue() 로 promise가 resolve하는 값을 조작함. • jest.mock()으로 특정 모듈을 mocking함.
-Mock functions (assertions)
• toHaveBeenCalled - 이 함수가 호출되었는지 검증.
• toHaveBeenCalledWith(arg1, arg2, ...) - 이 함수가 특정 인자와 함께 호출되었는지 검증.
• toHaveBeenLastCalledWith(arg1, arg2, ...) - 마지막으로 특정 인자와 함께 호출되었는지 검증.
-Lifecycle functions
• beforeEach
• afterEach
• beforeAll
• afterAll

-Grouping
• describe()
• test()

-Snapshot testing
• toMatchSnapshot()을 호출하면, 기존에 스냅샷이 없었을 경우 .snap 파일을 만듦.
• 기존 스냅샷이 있을 경우, 새로운 스냅샷과 비교하여 변경 사항이 있으면 테스트는 실패함.
• toMatchInlineSnapshot()을 호출하면 별도의 스냅샷 파일을 만들지 않음. 이 경우,어떻게 스냅샷이 쓰였는 지를 하나의 파일 안에서 알수 있게 됨.
4. react-testing-library
• 테스트가 소프트웨어가 사용되는 모습을 닮을수록, 테스트를 더욱 신뢰할 수 있게 됨.
• The more your tests resemble the way your software is used, the more confidence they can give you.
• React 컴포넌트의 특정 메서드나 상태를 테스트하는 게 아니라, 실제 유저가 사용하는 방식대로 테스트하는 접근.
• 유저가 페이지에서 어떤 DOM 요소에 접근하는 방법을 흉내냄.
• 이 방식으로 테스트 코드를 작성하면, 내부 구현이 바껴도 테스트가 깨지지 않음.
• React 컴포넌트가 렌더링한 결과에 대한 접근만 가능함.
• 쿼리는내부상태나내부메서드에접근할수없게설계됨.
-react-testing-library의 쿼리 (get)
• getBy 관련 쿼리는 원하는 요소를 찾지 못 할 경우나 여러 개의 요소를 찾을 경우 에러를 던짐.
• getAllBy 관련 쿼리는 여러 요소를 찾아 배열을 반환한다. 원하는 요소를 찾지 못할 경우 에러를 던짐.
• 원소가 반드시 페이지에 존재해야만 하는 경우 활용함.
-react-testing-library의 쿼리 (find)
- findBy 관련 쿼리는 원하는 원소가 없더라도 비동기적으로 기다림.
- 여러 원소를 찾거나, 정해진 timeout동안 찾지 못하면 에러를 던짐.
- findAllBy 관련 쿼리는 여러 원소를 검색해 배열을 반환한다. 정해진 timeout동안
- 찾지 못하면 에러를 던짐.
- Promise를 리턴하며, 실패시 reject, 성공시 resolve.
- 어떤 유저의 동작 후에 등장하는 원소 등을 테스트 하고자 할 때 활용함.
-react-testing-library의 쿼리 (query)
• queryBy 관련 쿼리는 getBy와 비슷하게 원소를 찾아 반환하나, 못찾을 경우 에러를 던지지 않고 null을 반환함. 여러 원소를 찾으면 에러를 던짐.
• queryAllBy 관련 쿼리는 getAllBy와 비슷하게 여러개의 원소를 찾아 배열로 반환하나, 하나도찾지못하면에러대신빈배열을반환함.
• 특정 요소를 찾을 수 없음을 assertion의 기준으로 둘 때 활용됨.
-react-testing-library의 쿼리 (container)
• container는 컴포넌트를 렌더한 결과를 감싸는 원소.
• queryselector(), querySelectorAll()을 이용해 selector 문법으로 원소를 선택할 수 있음.
-jest-dom
• react-testing-library는 jest를 확장하여, 좀더 쓰기 편한 assertion을 제공함.
• toBeInTheDocument(), toHaveValue(), toBeDisabled(), toBeVisible() 등, DOM 테스팅에 특히 유용한 assertion 메서드를 제공함.
5. 쿼리의 우선순위
• 유저가 페이지를 이동하는 방식에 가까운 쿼리일수록 우선순위가 높음.
• 접근성 높은 HTML을 작성할수록 테스트가 용이한 코드가 됨.
-쿼리의 우선순위 (ByRole)
• accessibility tree에 있는 요소들을 기준으로 원소를 찾음.
• 유저가 웹페이지를 사용하는 방식을 가장 닮은 쿼리.
• 동일한 role을 가진 경우, accessible name을 이용해 원소를 구별함.
• 임의로 role 혹은 aria-*을 부여하는 것을 지양함.
• 자주 사용되는 Role - button, checkbox, listitem, heading, img, form, textbox, link
• 자주 사용되는 accessible name button - 텍스트
label - 텍스트
a-텍스트
img - alt 텍스트
-쿼리의 우선순위 (Text)
• 유저가볼수있는Text값을기준으로쿼리를찾음.
• ByLabelText – label과 연관된 원소를 찾음.
• ByPlaceholderText – placeholder와 연관된 원소를 찾음.
• ByText – 주어진 Text와 연관된 원소를 찾음.
• ByDisplayValue – input, textarea, select 등의 value를 기준으로 원소를 찾음.
-쿼리의 우선순위 (semantic queries)
• 유저에게 보이지 않지만, 접근성 스펙에 적합한 alt, title을 이용하여 원소를 검색함.
• ByAltText – img, area, input등의 alt 속성으로 원소를 검색함.
• ByTitle – title 속성으로 원소를 검색함.
-쿼리의 우선순위 (Test ID)
• data-testid 속성을 원하는 원소에 지정하고, 쿼리를 이용해 찾음.
• 유저가 해당 속성을 기반으로 화면의 요소를 찾는 게 아니므로 우선순위가 낮음.
• 다른 쿼리로 테스트를 작성 할 수 없을 때 이 쿼리를 백도어로 활용함.

6. 유저 이벤트
-user-event
• 내장 이벤트 함수인 fireEvent, createEvent를, 좀더 직관적이고 범용적으로 사용할 수 있도록 만든 라이브러리.
• click, type, keyboard, upload, hover, tab 등 유저가 실제로 웹페이지를 사용하며 만드는 이벤트를 메서드로 제공함.
-user-event (click)
-user-type (type)
'React' 카테고리의 다른 글
[React] React 앱 빌드와 배포 (0) | 2022.12.06 |
---|---|
[React] Server Side Rendering (0) | 2022.12.06 |
[React] 상태관리 (0) | 2022.12.01 |
[React] 비동기 통신과 Promise (0) | 2022.12.01 |
[React] SPA 와 라우팅 (0) | 2022.12.01 |