Kotlin으로 ☕ Espresso UI 테스트 기반 잘 다지는 법 #1 - 테스트 케이스
⚙️ 기본 설정
Espresso (에스프레소)
는 구글에서 제공하는 안드로이드 UI 테스트 라이브러리이다. 3.x 버전부터는 AndroidX Library
에 통합되어 제공되고 있다. 기본적인 설정은 안드로이드 개발 코드 안에서 직접 환경설정할 수 있다.
build.gradle
android { defaultConfig { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } } // https://developer.android.com/jetpack/androidx/releases/test def androidxTest = '1.2.0' def espresso = '3.2.0' dependencies { ... androidTestImplementation 'androidx.test:core:${androidxTest}' androidTestImplementation 'androidx.test:runner:${androidxTest}' androidTestImplementation 'androidx.test:rules:${androidxTest}' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:${espresso}' androidTestImplementation 'androidx.test.espresso:espresso-intents:${espresso}' androidTestImplementation 'androidx.test.espresso:espresso-contrib:${espresso}' androidTestImplementation 'androidx.test.espresso:espresso-idling-resource:${espresso}' androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' }
🚀 기본을 넘어서, 실용적인 코드로
이미 안드로이드 개발 문서에는 처음 에스프레소 테스트를 설정하는 방법이 잘 나와있다. 블로그도 여럿 있다. 테스트 자동화에서 가장 중요한 부분은 Stability (안정성)
과 Maintainability (유지/보전성)
이다. 계속해서 변화하는 앱에 따라 테스트도 관리해주어야 한다. 이를 보다 쉽고 빠르게 하기 위해, 기본적인 부분보다는, 더 실용적으로 기반을 다질 수 있는 코드를 보여주려 한다.
테스트를 Pass도 중요하지만, Fail했을때 디버깅 또한 중요하다. 이를 수월하게 해주는 첫 스텝은 바로 스크린샷이다.
FailureTestWatcher.kt
class FailureTestWatcher : TestWatcher() { override fun failed(e: Throwable?, description: Description) = takeScreenshot(description) private val screenshotFolder = File("/sdcard/screenshots") private fun prepareScreenshotPath() { runCatching { screenshotFolder.mkdirs() }.onFailure { Log.w("Failed to create the screenshot folder $screenshotFolder: $it") } } private fun takeScreenshot(description: Description) { prepareScreenshotPath() val capture = Screenshot.capture() val imageFile = File(screenshotFolder, "${description.methodName}_${Date().time}.png") runCatching { BufferedOutputStream(FileOutputStream(imageFile)).use { capture.bitmap.compress(capture.format, 100, it) } }.onFailure { Log.w("Failed to save a screenshot on test failure") } } }
위와 같이 테스트 실패 시 스크린샷을 찍는 Class를 설정해준다. 이를 기본 테스트 베이스를 설정해놓고, @Rule 훅에 연결해주면 된다.
TestBase.kt
abstract class TestBase { @Rule @JvmField val activityRule = ActivityTestRule(MainActivity::class.java) @Rule @JvmField val test = TestName() @Rule @JvmField val failureWatcher = FailureTestWatcher() @Before internal fun internalSetup() { setUp() } abstract fun setUp() @After internal fun internalTearDown() { tearDown() } abstract fun tearDown() }
또한, Context를 설정해줘, 테스트 수행 시 activity 레벨에서 관리가 되고, 정보를 관리할 수 있도록 설정해주면, 관리가 수월해진다.
TestContext.kt
private const val EXPLICIT_WAIT_TIME = 1000L class TestContext(private val instrumentation: Instrumentation) { val currentActivity: Activity get() { var firstResumedActivity: Activity? = null onIdle() instrumentation.runOnMainSync { firstResumedActivity = ActivityLifecycleMonitorRegistry .getInstance() .getActivitiesInStage(RESUMED) .last() } return firstResumedActivity!! } fun waitForActivityToAppear(activity: String) { while (activity !in currentActivity.localClassName) { runCatching { SystemClock.sleep(EXPLICIT_WAIT_TIME) } } } fun waitForActivityToDisappear(activity: String) { while (activity in currentActivity.localClassName) { runCatching { SystemClock.sleep(EXPLICIT_WAIT_TIME) } } } }
이를 매 테스트 설정 시 관리해주면 테스트 코드를 짜기 수월해진다. 안드로이드 설정 Permission 관리도 여기서 가능하다.
TestBase.kt
abstract class TestBase { lateinit var context: TestContext @Rule @JvmField val activityRule = ActivityTestRule(MainActivity::class.java) ... @Rule @JvmField var grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE ) @Before internal fun internalSetup() { context = TestContext(InstrumentationRegistry.getInstrumentation()) setUp() } ... }
이 베이스를 새로운 테스트 class를 생성할 때마다 베이스로 설정해주면, 한 곳에서 관리가 되는 편리함이 생긴다.
SampleTest.kt
class SampleTest : TestBase() { override fun setUp() { ... } @Test fun scenario1() { ... } }
'👨🏻💻 QA이야기 > 📱 모바일자동화' 카테고리의 다른 글
Kotlin으로 ☕ Espresso UI 테스트 기반 잘 다지는 법 #2 - Matchers (0) | 2020.04.19 |
---|---|
Swift로 🍏 UI XCTest 기반 잘 다지는 법 #2 - Action (0) | 2020.04.04 |
Swift로 🍏 UI XCTest 기반 잘 다지는 법 #1 - 테스트 케이스 (0) | 2020.04.04 |
🥒 Cucumber 이해하고 잘 쓰는 방법 (0) | 2020.04.03 |
🗳️ QA의 모바일 자동화를 위한 개발환경 (0) | 2020.04.01 |
댓글
이 글 공유하기
다른 글
-
Kotlin으로 ☕ Espresso UI 테스트 기반 잘 다지는 법 #2 - Matchers
Kotlin으로 ☕ Espresso UI 테스트 기반 잘 다지는 법 #2 - Matchers
2020.04.19🏤 나만의 관리소 만들기 Espresso에서 Matcher란 어플리케이션 내 element들의 패턴을 해석하여 원하는 작업을 수행하는 엔진이다. 이는 기본 Espresso 라이브러리에서 곧장 불러다가 사용이 가능하지만, 매번 패키지를 import 하고, 여러 가지 작업을 연달아 수행하다 보면 코드가 굉장히 지저분하고 길어질 수 있다. 베이스 Interface를 생성하여 이를 관리해주면, 테스트 코드가 보다 보기 쉽고 간편해지며, 관리 또한 수월해진다. BaseViewMatchers.kt interface BaseViewMatchers { fun onView(viewMatcher: Matcher): ViewInteraction = Espresso.onView(viewMatcher) fun onData(vi… -
Swift로 🍏 UI XCTest 기반 잘 다지는 법 #2 - Action
Swift로 🍏 UI XCTest 기반 잘 다지는 법 #2 - Action
2020.04.04💥 Extension 잘 사용하기 Swift의 extension을 잘 사용하면, 테스트 코드가 매우 깔끔해지고, 관리하기도 쉬워지며 새로운 테스트를 작성하기도 수월해진다. 기본적인 코드는 XCUIApplication().tabBars.buttons["Home"].tap() 이러한 방식이다. 매우 간단하지만, XCUIApplication().app()을 매번 불러야하며, Page Object 컨셉을 적용하면, 더욱 코드가 더러워진다. XCTest 라이브러리의 Action Extension을 만들어서 관리해주면, 매우 간편하게 코드를 만들수 있다: extension XCTest { struct UIApplication { static var app: XCUIApplication? } var app: XCUI… -
Swift로 🍏 UI XCTest 기반 잘 다지는 법 #1 - 테스트 케이스
Swift로 🍏 UI XCTest 기반 잘 다지는 법 #1 - 테스트 케이스
2020.04.04❗ 처음 세우는 기둥이 중요하다 뭐든지 처음 기반을 잘 세워두면 이후가 안정적이고 편해진다. iOS/macOS 어플리케이션의 테스팅 프레임워크인 XCTest는 UI 테스팅도 가능하다. Xcode에서는 레코딩 툴도 갖춰져 있어, 자동으로 테스트 코드를 짜주는 기능도 있다. (물론 이 코드는 그리 안정적인 코드는 되지 못하지만 레퍼런스 정도로 사용하기에 좋다.) 🧱 첫 기둥이 되는 Base 테스트 케이스 XCTestCase 라이브러리를 사용하여 베이스를 잘 셋업 해놓으면, 추후 여러 테스트들을 관리하기가 수월해진다. class BaseTestCase: XCTestCase { override func setUp() { super.setUp() // 시스템 알림창이 뜰 경우를 대비해 핸들링 코드를 셋업에 입력해… -
🥒 Cucumber 이해하고 잘 쓰는 방법
🥒 Cucumber 이해하고 잘 쓰는 방법
2020.04.03🥒 Cucumber Cucumber (큐컴버) 는 Behaviour-Driven Development (BDD) 지원용 툴이다. BDD는 소프트웨어 개발에서 비지니스와 테크니컬한 부분 사이의 문제를 줄이기 위해 시작되었다. 협옵을 통해 문제는 해결하고, 작은 주기의 빠른 흐름으로 피드백을 늘리는 동시에 문서화도 할수 있는 방식이다. 애자일 환경에서 많이 사용되며, 작지만 여러개의 User story들이 애자일 좋은 개발 환경을 구축하는데 도움을 준다. 보통은 Gherkin (절킨) 이라는 문법을 사용한다. 이는 Step Definition (스텝 데피니션) 시스템으로, '사람이 읽을 수 있는' 방식으로 적게된다. 명확한 실행 사양, Cucumber를 이용한 테스트 자동화 및 실제로 어떻게 동작하는지 문서…
댓글을 사용할 수 없습니다.