Jetpack Compose의 시맨틱스(Semantics)와 UI 테스트
Jetpack Compose의 시맨틱스(Semantics)와 UI 테스트
Jetpack Compose는 시맨틱스(Semantics) 시스템을 통해 UI 요소의 시각적 외형 이상의 **의미(meaning)**를 정의합니다. 이 시스템은 접근성(Accessibility) 서비스와 테스트 프레임워크 양쪽에서 활용되며, 구현 세부 사항에 의존하지 않고도 UI 노드를 탐색하고, 상호작용하고, 검증할 수 있는 구조화된 방법을 제공합니다. 시맨틱스 기반 테스트를 처음 접하시는 분이라도 걱정하실 필요 없습니다. 이 개념을 제대로 이해하시면 테스트 코드의 유지보수성과 접근성을 동시에 높일 수 있습니다.
이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.
- 시맨틱스 트리(semantics tree)가 무엇인지, 그리고 컴포지션 트리와 어떤 관계를 가지는지 설명할 수 있습니다.
- 테스트 프레임워크가 시맨틱스 속성을 사용하여 UI 노드를 탐색하고 상호작용하는 방식을 파악할 수 있습니다.
Modifier.semantics를 활용하여 커스텀 컴포넌트에 의미를 부여하는 방법을 적용할 수 있습니다.- 병합된(merged) 시맨틱스 트리와 병합되지 않은(unmerged) 시맨틱스 트리의 차이를 구분하고, 각각의 사용 시점을 이해할 수 있습니다.
- 내부 구조가 아닌 시맨틱스 속성을 기반으로 Compose UI 테스트를 작성할 수 있습니다.
시맨틱스 트리(Semantics Tree)
사용자에게 의미를 전달하는 모든 컴포저블은 시맨틱스 트리에 대응하는 노드를 가집니다. 이 트리는 컴포지션 트리와 병렬로 존재하며, 텍스트 내용, 역할(role), 토글 상태, 콘텐츠 설명(content description), 커스텀 접근성 액션 등의 메타데이터를 저장합니다. Text, Button, Switch 같은 표준 컴포넌트는 시맨틱스 속성을 자동으로 채워 줍니다.
테스트 프레임워크와 접근성 서비스는 모두 이 트리에서 정보를 읽습니다. 테스트에서 텍스트 내용이나 역할로 노드를 찾을 때, 컴포지션 트리나 렌더링된 픽셀이 아니라 시맨틱스 트리를 조회하는 것입니다. 이러한 분리는 의도적으로 설계된 것으로, 시맨틱스 트리는 UI가 내부적으로 어떻게 구현되었는지가 아니라 사용자에게 무엇을 의미하는지를 나타냅니다.
모든 컴포저블이 시맨틱스 노드를 가지는 것은 아닙니다. Box, Column, Row 같은 레이아웃 컨테이너는 명시적인 시맨틱스 어노테이션이 없는 한 트리에 나타나지 않습니다. 사용자에게 보이는 의미나 상호작용 동작을 가진 컴포저블만 시맨틱스 노드를 생성합니다. 이 점은 면접에서 "어떤 컴포저블이 시맨틱스 트리에 포함되는가?"라는 질문으로 이어질 수 있으므로 명확하게 이해해 두시는 것이 좋습니다.
노드 탐색과 상호작용
Compose 테스트 프레임워크는 SemanticsMatcher를 사용하여 시맨틱스 속성으로 노드를 탐색합니다. 텍스트, 콘텐츠 설명, 역할, 토글 상태, 또는 커스텀 시맨틱스 속성을 기준으로 매칭할 수 있습니다.
// Switch 역할을 가진 노드를 찾아 클릭 후 토글 상태를 검증
val mySwitch = SemanticsMatcher.expectValue(
SemanticsProperties.Role, Role.Switch
)
composeTestRule.onNode(mySwitch)
.performClick()
.assertIsOff()
위의 테스트는 Switch 역할을 가진 노드를 찾아 클릭한 뒤, 토글 상태가 꺼져 있는지 검증합니다. 여기서 주목할 점은, 테스트 코드가 어떤 컴포저블 함수 이름이나 레이아웃 구조도 참조하지 않는다는 것입니다. 전적으로 시맨틱스 수준에서 동작하기 때문에, 컴포저블 계층 구조를 리팩토링하더라도 테스트가 깨지지 않습니다. 이러한 특성이 바로 시맨틱스 기반 테스트의 핵심 강점입니다.
커스텀 컴포넌트에 시맨틱스 추가하기
기본 제공 컴포넌트는 시맨틱스를 자동으로 처리하지만, 직접 그리거나 저수준 프리미티브로 구성된 커스텀 컴포넌트에는 명시적으로 시맨틱스 어노테이션을 추가해야 합니다. 시맨틱스 정보가 없으면 테스트 프레임워크와 접근성 도구가 해당 컴포넌트와 제대로 상호작용할 수 없습니다. 실무에서 커스텀 뷰를 많이 사용하는 팀일수록, 이 부분의 이해가 특히 중요합니다.