이 영역을 누르면 첫 페이지로 이동
스니펫 텔러 | Snippet Teller 블로그의 첫 페이지로 이동

스니펫 텔러 | Snippet Teller

페이지 맨 위로 올라가기

스니펫 텔러 | Snippet Teller

아이템이나 서비스 리뷰, 해외생활 등 좋은 정보와 이야기들을 짧고 읽기 쉽게 요약해, 빠르게 전달해 드립니다.

Kotlin으로 ☕ Espresso UI 테스트 기반 잘 다지는 법 #1 - 테스트 케이스

  • 2020.04.12 19:35
  • 👨🏻‍💻 QA이야기/📱 모바일자동화
반응형

 

 

⚙️ 기본 설정

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

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • Kotlin으로 ☕ Espresso UI 테스트 기반 잘 다지는 법 #2 - Matchers

    Kotlin으로 ☕ Espresso UI 테스트 기반 잘 다지는 법 #2 - Matchers

    2020.04.19
  • Swift로 🍏 UI XCTest 기반 잘 다지는 법 #2 - Action

    Swift로 🍏 UI XCTest 기반 잘 다지는 법 #2 - Action

    2020.04.04
  • Swift로 🍏 UI XCTest 기반 잘 다지는 법 #1 - 테스트 케이스

    Swift로 🍏 UI XCTest 기반 잘 다지는 법 #1 - 테스트 케이스

    2020.04.04
  • 🥒 Cucumber 이해하고 잘 쓰는 방법

    🥒 Cucumber 이해하고 잘 쓰는 방법

    2020.04.03
다른 글 더 둘러보기

정보

스니펫 텔러 | Snippet Teller 블로그의 첫 페이지로 이동

스니펫 텔러 | Snippet Teller

  • 스니펫 텔러 | Snippet Teller의 첫 페이지로 이동

검색

메뉴

    카테고리

    • 전체보기 (467)
      • 📋 일상이야기 (20)
      • 🇩🇪 베를린이야기 (42)
      • 🇰🇷 한국이야기 (3)
      • 🏅 리뷰이야기 (79)
        • 해외직구 (6)
        • 온라인서비스 (20)
        • 유럽생활 (15)
        • 그 외 (38)
      • 👨🏻‍💻 QA이야기 (19)
        • ⚙️ Quality Engineering (12)
        • 📱 모바일자동화 (7)
      • 🎗 생각하는 글 (49)
      • 🎮 게임정보 (253)
    반응형

    공지사항

    • 공지 - 블로그 공지사항

    방문자

    • 전체 방문자
    • 오늘
    • 어제

    티스토리

    • 티스토리 홈
    • 이 블로그 관리하기
    • 글쓰기

    정보

    무워 | hsoochun의 스니펫 텔러 | Snippet Teller

    스니펫 텔러 | Snippet Teller

    무워 | hsoochun

    블로그 구독하기

    • 구독하기
    • RSS 피드
    Powered by Tistory / Kakao. © 무워 | hsoochun. Designed by Fraccino.

    티스토리툴바