OverView
- Android UI Automator & Espresso 기반 UI 테스트를 위한 기반을 정리
개념
- UI Automator
- Android SDK에 내장된 UI 테스트 프레임 워크
- 앱 간 탐색 및 시스템 UI 와의 상호작용 등 앱 외부의 요소 테스트에 유용 (예 : 설정, 앱 실행, 알림 창 등)
- 디바이스 전체를 제어 가능
- Espresso
- Google에서 제공하는 Android UI 테스트 프레임워크
- 앱 내부 View 요소(버튼, 텍스트 등)와 상호작용을 자동화
- 안정적이고 동기화된 테스트 환경을 제공
- 차이점
- Espresso 는 앱 내부 테스트에 특화, UI Automator는 시스템 UI를 포함한 전체 디바이스 제어 가능
테스트 모듈 관리 전략
- 공통 테스트 코드를 위한 testing 모듈
- 테스트 관련 유틸리티 (예: Fake, Mock, Test Rule) 를 공통으로 사용한다면, testing 모듈에 배치
- shared module 로 사용되며 다른 feature 모듈에서 의존성을 추가하여 활용
- 유틸리티성 테스트 코드나 공통적인 테스트 의종성을 여기에 정의
- 공통적인 테스트 의존성 배치
-
dependencies { // 공통적으로 사용하는 Compose 테스트 라이브러리 implementation "androidx.compose.ui:ui-test-junit4:1.0.5" debugImplementation "androidx.compose.ui:ui-test-manifest:1.0.5" // 공통적으로 사용하는 Espresso implementation "androidx.test.espresso:espresso-core:3.4.0" }
- 테스트 유틸리티등 제공
-
object TestUtils { fun createFakeRepository(): Repository { return FakeRepository() } }
- 각각의 feature 모듈에서 테스트
- UI 관련 테스트 (Espresso/Compose))는 각 feature모듈에 작성
- 이 방식은 테스트를 해당 모듈의 범위 내로 한정
- 해당 모듈에서만 테스트 의존성 추가
-
dependencies { androidTestImplementation project(":testing") // 공통 테스트 모듈 의존성 추가 androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.0.5" androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0" }
- UI 테스트 및 특정 비즈니스 로직 테스트는 각 feature 모듈에서 작성
-
@RunWith(AndroidJUnit4::class) class FeatureXTest { @Test fun testSomeFeature() { // Compose or Espresso tests here } }
핵심 요소
- UI Automator
- UiDevice : 디바이스 제어
- UiSelector : UI 요소를 선택
- UiObject : 선택된 UI 요소의 동작 수행
- Espresso:
- onView: 특정 View를 찾음.
- ViewMatchers: 뷰의 속성 매칭 (예: withId, withText).
- ViewActions: 동작 수행 (예: click).
- ViewAssertions: 결과 검증 (예: matches).
- Compose Testing 주요 구성
- createAndroidComposeRule: Compose 테스트 환경 설정.
- onNodeWithText: 특정 텍스트를 가진 Compose 노드 탐색.
- performClick: 노드에 클릭 동작 수행.
- assertIsDisplayed: 노드가 화면에 표시되는지 검증.
간단 설명
- UiDevice 초기화:
- UiDevice: 디바이스를 제어하는 핵심 객체.
- getInstance: 현재 테스트 환경에 연결된 디바이스 객체를 가져옴.
- val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- 홈 버튼 초기화:
- 디바이스의 홈 화면으로 이동하여 초기 상태를 설정.
- device.pressHome()
- 앱 실행:
- UiSelector().descriptionContains("MyApp"): 앱의 이름이나 설명으로 앱 실행기를 탐색.
- clickAndWaitForNewWindow(): 클릭 후 새로운 창(화면)이 열릴 때까지 대기.
- val appLauncher = device.findObject(UiSelector().descriptionContains("MyApp")) appLauncher.clickAndWaitForNewWindow()
- 버튼 클릭:
- UiSelector().text("Next"): 버튼의 텍스트가 "Next"인 요소를 탐색.
- click(): 해당 요소를 클릭.
- val nextButton = device.findObject(UiSelector().text("Next")) nextButton.click()
- 다음 화면 확인:
- 다음 화면의 특정 요소(예: 텍스트 "Next Screen")가 존재하는지 확인.
- assert: 조건을 만족하지 않으면 테스트 실패.
- val nextScreenText = device.findObject(UiSelector().textContains("Next Screen")) assert(nextScreenText.exists())
화면 이동의 추가 고려사항
- 앱 내 Navigation 확인:
- UiSelector().resourceId("com.example:id/uniqueId"): 특정 View의 리소스 ID로 탐색.
- View의 고유 리소스를 활용해 더 안정적으로 요소 탐색.
- 대기 조건:
- 비동기 작업 대기:
- 최대 5초 동안 "Next Screen" 텍스트가 표시되기를 기다림.
- device.wait(Until.hasObject(By.text("Next Screen")), 5000)
- 비동기 작업 대기:
- 스크롤 필요 시:
- 긴 목록에서 항목을 찾으려면 UiScrollable 사용:
- val scrollable = UiScrollable(UiSelector().scrollable(true)) scrollable.scrollTextIntoView("Next")
반응형
'Android' 카테고리의 다른 글
안드로이드 UI의 진화: ListView에서 RecyclerView, 그리고 Compose 까지 [Part.2 RecyclerView] (6) | 2025.01.21 |
---|---|
안드로이드 UI의 진화: ListView에서 RecyclerView, 그리고 Compose까지 [Part 1 ListView] (3) | 2025.01.21 |
Android Context 정리 (2) | 2024.12.08 |
[Android] Dialog Dim 효과 처리 방법 (0) | 2024.11.29 |
[Android] Compose Dialog 사용 (0) | 2024.11.18 |