-
안드로이드 앱 테스트 기본 - 2 (UI Test예제 포함)안드로이드 학습/Android 기술면접 대비 2024. 12. 7. 17:20
안드로이드에서 UI 테스트는 아래 방법들이 있다
- Espresso: 구글이 제공하는 UI 테스트 프레임워크.
- UIAutomator: 시스템 앱을 포함한 더 넓은 범위를 테스트할 때 사용.
- Compose Test: Jetpack Compose UI를 테스트하는 전용 API.
- 그 외에 Robotium, Calabash, Robolectric 등등이 있다.
- Espresso 공식 샘플 ( Espresso 뿐만 아니라 UIAutomator, JUnit4 등 다양한 샘플 보유)
1. Espresso
Espresso는 앱의 UI와 테스트를 자동으로 동기화 해준다. Espresso는 3가지 기본 component를 갖는다.
- ViewMatchers - 현재 뷰 계층 구조에서 뷰를 찾을 수 있도록 지원합니다.
- ViewActions - 뷰에 대한 작업을 수행할 수 있도록 지원합니다.
- ViewAssertions - 뷰의 상태를 검증할 수 있도록 지원합니다.
테스트의 기본적인 구조
onView(ViewMatcher) .perfrom(ViewAction) .check(ViewAssertion);
1-1. 주요 Espresso 메서드 요약
1) ViewActions : 액션 (Action) 메서드
- perform(click()) : 클릭
- perform(typeText("text")) : 텍스트 입력
- closeSoftKeyboard() : 소프트 키보드 닫기
2) ViewMatchers : 매칭 (Matcher) 메서드
- withId(R.id.viewId) : ID로 찾기
- withText("text") : 텍스트로 찾기
- withHint("hint") : 힌트로 찾기
3) ViewAssertions : 확인 (Assertion) 메서드
- check(matches(withText("text"))) : 텍스트 확인
- check(matches(isDisplayed())) : 표시 여부 확인
- check(matches(not(isEnabled()))) : 비활성화 여부 확인
1-2) 예제 :
build.gradle (:app)
android { defaultConfig { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } } dependencies { androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test:rules:1.5.0") }
Activity & Fragment
더보기<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/tv_ui_test_espresso" android:layout_width="58dp" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:text="Espresso Example" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/btn_ui_test_espresso" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="Hello Espresso" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/tv_ui_test_espresso" /> <EditText android:id="@+id/et_ui_test_espresso" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="15dp" android:hint="Enter text" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/btn_ui_test_espresso" /> </androidx.constraintlayout.widget.ConstraintLayout>
UiTest
더보기@RunWith(AndroidJUnit4::class) class UiTest { // Activity 테스트 하는 부분 @get:Rule val activityRule = ActivityScenarioRule(UiTestActivity::class.java) @Before fun before() { // setUp } @After fun after() { } @SuppressLint("CheckResult") @Test fun testActivityButtonClick() { // EditText onView(withId(R.id.et_ui_test_espresso)) .perform(closeSoftKeyboard()) .check(matches(isDisplayed())) // Button onView(withId(R.id.btn_ui_test_espresso)) .perform(click()) .check(matches(withText("Hello Espresso"))) // TextView onView(withId(R.id.tv_ui_test_espresso)) .check(matches(withText("Espresso Example"))); } @SuppressLint("CheckResult") @Test fun testFragmentButtonClick() { val scenario = launchFragmentInContainer<UiTestFragment>() // EditText onView(withId(R.id.et_ui_test_espresso_fragment)) .perform(closeSoftKeyboard()) .check(matches(isDisplayed())) // Button onView(withId(R.id.btn_ui_test_espresso_fragment)) .perform(click()) .check(matches(withText("Hello Espresso"))) // TextView onView(withId(R.id.tv_ui_test_espresso_fragment)) .check(matches(withText("Espresso Example"))); } }
2. UIAutomator
UIAutomator 역시 Espresso와 마찬가지로 안드로이드에서 UI를 테스트 할 수 있게 도와주는 라이브러리다.
2가지의 테스트 용도를 살펴보자면
- UIAutomator :
- 블랙박스 테스트, 두개 이상의 앱을 연동하여 테스트할 때 좋음
- 전체 시스템 및 다른 앱 제어 가능
- Espresso :
- 화이트박스 테스트, 한개의 앱만 테스트할 때 좋음
- UI 상호작용, 화면 전환, 뷰 검증
UIAutomator는 앱의 구현이 어떻게 되어 있는지 모른다고 한다. 앱 이름으로 앱을 실행 시키고, 어떤 버튼을 누르는지는 버튼 id정보나 텍스트 정보로 가능하게 한다. 그래서 현재 앱 말고도 다른 앱과 연동해서 테스트 가능하다.
build.gradle
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.3.0' // uiautomator androidTestImplementation 'androidx.test:runner:1.6.2'
Before Code :
더보기private const val BASIC_SAMPLE_PACKAGE = "com.aio.kotlin" private const val LAUNCH_TIMEOUT = 5000L private const val STRING_TO_BE_TYPED = "UiAutomator" @RunWith(AndroidJUnit4::class) class UiAutomatorTest { private lateinit var device: UiDevice @Before fun startMainActivityFromHomeScreen() { // Initialize UiDevice instance device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) // Start from the home screen device.pressHome() // Wait for launcher val launcherPackage: String = device.launcherPackageName assertThat(launcherPackage, notNullValue()) device.wait( Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT ) // Launch the app val context = ApplicationProvider.getApplicationContext<Context>() val intent = context.packageManager.getLaunchIntentForPackage( BASIC_SAMPLE_PACKAGE)?.apply { // Clear out any previous instances addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) } context.startActivity(intent) // Wait for the app to appear device.wait( Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT ) } }
테스트에서 UiDevice 메서드를 호출하여 현재 방향 또는 디스플레이 크기와 같은 다양한 속성의 상태를 나타냅니다.
테스트는 UiDevice 객체를 사용하여 기기 수준 작업을 실행할 수 있습니다.
Test Code :
더보기@Test fun testLaunchCalculator() { device.findObject(By.text("기초").clazz("android.widget.TextView")).click() val allowButton: UiObject2 = device.wait( Until.findObject(By.text("허용").clazz("android.widget.Button")), 5000 // 최대 5초 기다림 ) allowButton.click() device.wait( Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(1)), LAUNCH_TIMEOUT ) // 클릭 후 3초 대기 Thread.sleep(3000) // 3초 대기 }
Before에서 Activity에 진입했다면 보여지는 Activity 내에서 id나 View의 text 이름으로 action을 수행할 수 있다.
@Test fun testFindById() { // ID로 버튼을 찾기 (예: "com.example.app:id/btnConfirm") val button: UiObject2 = device.wait( Until.findObject(By.res("com.example.app:id/btnConfirm")), 5000 // 최대 5초 대기 ) // 버튼이 존재하면 클릭 button?.click() }
@Test fun testFindByText() { // 텍스트로 버튼을 찾기 (예: "확인") val button: UiObject2 = device.wait( Until.findObject(By.text("확인")), 5000 // 최대 5초 대기 ) // 버튼이 존재하면 클릭 button?.click() }
부분 포함된 text로도 가능하다.
@Test fun testFindByTextContains() { // 텍스트 일부로 버튼을 찾기 (예: "확인"이 포함된 텍스트) val button: UiObject2 = device.wait( Until.findObject(By.textContains("확인")), 5000 // 최대 5초 대기 ) // 버튼이 존재하면 클릭 button?.click() }
객체가 실행 가능한 메소드
테스트에서 UiObject2 객체를 가져오면 다음에서 메서드를 호출할 수 있습니다. UI 구성요소에서 사용자 상호작용을 실행하는 UiObject2 클래스 해당 객체로 표시됩니다. 다음과 같은 작업을 지정할 수 있습니다.
'안드로이드 학습 > Android 기술면접 대비' 카테고리의 다른 글
안드로이드 DataStore와 SharedPreference (0) 2025.02.19 안드로이드 아키텍처 (MVC) (0) 2024.12.09 안드로이드 Coroutine Flow - 3 (StateFlow) (0) 2024.11.28 안드로이드 Coroutine Flow - 2 (Flow 사용) (0) 2024.11.28 안드로이드 Coroutine Flow - 1 (Flow란?) (0) 2024.11.27