어떻게 쿼리를 사용해야 할까?
React Native Testing Library는 테스트에 적합한 뷰를 찾기 위해 다양한 쿼리 유형을 제공합니다. 하지만 쿼리의 수가 많아 혼란스러울 수 있습니다. 이 가이드는 테스트 시나리오에 맞는 적절한 쿼리를 선택하는 데 도움을 주기 위해 작성되었습니다.
쿼리의 구성 요소
각 쿼리는 두 부분으로 구성됩니다: 쿼리의 **변형(variant)**과 **조건(predicate)**으로, 이 둘은 쿼리 이름에서 "by"라는 단어로 구분됩니다.
예를 들어, 다음 쿼리를 살펴보세요:
getBy*
는 쿼리 변형입니다.*ByRole
는 쿼리 조건입니다.
쿼리 변형
쿼리 변형은 일치하는 요소의 예상 수와 타이밍을 설명하며, 반환 유형이 다를 수 있습니다.
쿼리 변형은 일치하는 요소의 개수와 타이밍을 설명하며, 반환 타입이 다릅니다.
변형 | Assertion | 반환 타입 | 비동기 여부 |
---|---|---|---|
getBy* | 정확히 하나의 일치하는 요소 |
| 아니오 |
getAllBy* | 하나 이상의 일치하는 요소 |
| 아니오 |
queryBy* | 0개 또는 1개의 일치하는 요소 |
|
|
queryAllBy* | Assertion 없음 |
| 아니오 |
findBy* | 정확히 하나의 일치하는 요소 |
| 예 |
findAllBy* | 최소 하나 이상의 일치하는 요소 |
| 예 |
쿼리는 일치하는 요소의 수에 대한 암묵적 단언으로 작동하며, 단언이 실패하면 오류를 발생시킵니다.
관용적 쿼리 변형
관용적 쿼리 변형은 테스트의 의도와 일치하는 요소 수를 명확히 표현하며, 단언이 실패할 경우 유용한 오류를 던져 문제를 진단하는 데 도움이 됩니다.
여기 관용적 쿼리 변형을 선택하는 일반적인 가이드라인이 있습니다:
getBy*: 하나의 일치하는 요소가 예상되는 경우 가장 일반적으로 사용합니다. 다른 쿼리는 특정한 경우에만 사용하세요.
findBy*: 요소가 아직 요소 트리에 없지만 비동기 작업의 결과로 추가될 것으로 예상되는 경우 사용합니다.
getAllBy* (및 비동기 작업의 경우 findAllBy*): 여러 개의 일치하는 요소가 예상되는 경우 사용합니다(예: 리스트에서).
queryBy*: 요소가 존재하지 않아야 할 때 사용하며, 예를 들어
not.toBeOnTheScreen()
매처와 함께 사용할 수 있습니다.queryAllBy*: 일치하는 요소 수에 대한 단언이 없으므로 일반적인 테스트에서는 피하는 것이 좋습니다. 그러나 재사용 가능한 사용자 정의 테스트 도구를 만들 때는 유용할 수 있습니다.
쿼리 조건
쿼리 조건은 주어진 요소를 일치시킬지 여부를 결정하는 방법을 설명합니다.
조건 | 지원 요소 | 검사하는 속성 |
---|---|---|
ByRole | 모든 호스트 요소 |
|
ByLabelText | 모든 호스트 요소 |
|
ByDisplayValue |
|
|
ByPlaceholderText |
|
|
ByText |
| 자식 요소( |
ByHintText | 모든 호스트 요소 |
|
ByTestId | 모든 호스트 요소 |
|
관용적 쿼리 조건
올바른 쿼리 조건을 선택하면 테스트의 의도를 더 잘 표현할 수 있으며, 테스트가 사용자가 코드(컴포넌트, 화면 등)와 상호작용하는 방식을 최대한 반영할 수 있게 됩니다. 또한 대부분의 조건은 적절한 접근성 속성의 사용을 장려하여 View 요소로 구성된 요소 트리 위에 의미적 계층을 추가합니다.
쿼리 조건은 다음과 같은 우선 순위로 사용하는 것이 좋습니다.
By Role 쿼리
가장 첫 번째이자 가장 유연한 조건은 ByRole입니다. 이 조건은 요소의 의미적 역할에서 시작하여 추가 옵션으로 더 좁힐 수 있습니다. React Native는 두 가지 역할 시스템을 가지고 있습니다. 하나는 role
속성을 기반으로 한 웹/ARIA 호환 시스템이고, 다른 하나는 accessibilityRole
속성을 기반으로 한 전통적인 시스템입니다. 이 중 어느 것을 사용해도 됩니다.
대부분의 경우, 접근성 역할을 명시적으로 설정해야 합니다(또는 컴포넌트 라이브러리가 이를 설정할 수 있습니다). 이러한 역할은 보조 기술(예: 화면 판독기)과 테스트 코드가 뷰 계층 구조를 더 잘 이해할 수 있게 합니다.
자주 사용되는 역할로는 다음이 있습니다:
alert
: 사용자에게 중요한 텍스트를 표시할 때 사용(예: 오류 메시지)button
checkbox
&switch
: 켜짐/꺼짐 컨트롤heading
(header): 콘텐츠 섹션의 헤더(예: 내비게이션 바의 제목)img
(image)link
menu
&menuitem
progressbar
radiogroup
&radio
searchbox
(search)slider
(adjustable)summary
tablist
&tab
text
: 변경할 수 없는 정적 텍스트toolbar
: 액션 버튼을 위한 컨테이너
Name 옵션
역할과 접근 가능한 이름(= 요소의 접근성 레이블 또는 텍스트 콘텐츠)을 일치시키기 위해 name 옵션을 추가하는 경우가 많습니다.
몇 가지 예시는 다음과 같습니다.
시작 버튼:
getByRole("button", { name: "Start" })
무음 모드 스위치:
getByRole("switch", { name: "Silent Mode" })
화면 헤더:
getByRole("header", { name: "Settings" })
실행 취소 메뉴 항목:
getByRole("menuitem", { name: "Undo" })
오류 메시지:
getByRole("alert", { name: /Not logged in/ })
Text Input 쿼리
TextInput
요소를 쿼리하는 것은 고유한 도전 과제를 제공합니다. TextInput
요소에 대한 별도의 역할이 없기 때문입니다. TextInput
에 할당할 수 있는 searchbox/search
역할이 있지만, 이는 검색 입력의 맥락에서만 사용되어야 하므로 다른 텍스트 입력에는 해당 역할이 없습니다.
따라서 관련 텍스트 입력을 찾기 위해 다음 쿼리를 사용할 수 있습니다.
ByLabelText: 요소의 접근성 레이블과 일치합니다. 이 쿼리는 TextInput 요소를 포함한 모든 호스트 요소와 일치합니다.
ByPlaceholderText:
TextInput
요소의placeholder
와 일치합니다. 이 쿼리는TextInput
요소에만 적용됩니다.ByDisplayValue:
TextInput
요소의 현재(또는 기본) 값과 일치합니다. 이 쿼리도TextInput
요소에만 적용됩니다.
기타 접근성 쿼리
이러한 쿼리는 시각적으로나 보조 기술(예: 화면 판독기) 측면에서 앱의 사용자 경험을 반영합니다.
이러한 쿼리에는 다음이 포함됩니다:
ByText: 요소의 텍스트 콘텐츠와 일치합니다. 이 쿼리는 Text 요소와만 일치합니다.
ByLabelText: 요소의 접근성 레이블과 일치합니다.
ByHintText: 요소의 접근성 힌트와 일치합니다.
Test ID 쿼리
마지막 조건으로, testID
속성을 사용하여 관련 뷰를 찾을 수 있습니다. ByTestId 조건을 사용하는 것은 가장 유연하지만,사용자 경험을 반영하지 않기 때문에 주의해야 합니다.
테스트 ID를 사용하는 것은 다양한 문제로 인해 다른 방법을 통한 뷰 쿼리가 어려운 종단 간(end-to-end) 테스트에서 널리 사용되는 기법입니다. 그럼에도 불구하고, 우리는 여전히 권장되는 RNTL 쿼리를 사용하는 것이 통합 및 컴포넌트 테스트를 더 신뢰할 수 있고 견고하게 만들 것이라고 권장합니다.