1. 시작하기 전에
이전 Codelab에서는 단위 테스트를 만들고 실행하는 방법을 알아봤습니다. 이 Codelab에서는 계측 테스트에 중점을 둡니다. 계측 테스트의 모양과 작성하는 방법을 확인할 수 있습니다.
기본 요건
- Android 스튜디오에서 프로젝트를 만들어 보았습니다.
- Android 스튜디오에서 코드를 작성해 보았습니다.
- Android 스튜디오에서 프로젝트를 탐색해 보았습니다.
- Android 스튜디오에서 간단한 단위 테스트를 작성해 보았습니다.
학습할 내용
- 계측 테스트의 형태
- 계측 테스트를 실행하는 방법
- 계측 테스트를 작성하는 방법
필요한 항목
- Android 스튜디오가 설치된 컴퓨터
- Tip Time 앱의 솔루션 코드
이 Codelab의 시작 코드 다운로드
이 Codelab에서는 이전 솔루션 코드의 Tip Time 앱에 계측 테스트를 추가합니다.
- 프로젝트에 제공된 GitHub 저장소 페이지로 이동합니다.
- 브랜치 이름이 Codelab에 지정된 브랜치 이름과 일치하는지 확인합니다. 예를 들어 다음 스크린샷에서 브랜치 이름은 main입니다.
- 프로젝트의 GitHub 페이지에서 Code 버튼을 클릭하여 팝업을 엽니다.
- 팝업에서 Download ZIP 버튼을 클릭하여 컴퓨터에 프로젝트를 저장합니다. 다운로드가 완료될 때까지 기다립니다.
- 컴퓨터에서 파일을 찾습니다(예: Downloads 폴더).
- ZIP 파일을 더블클릭하여 압축을 해제합니다. 프로젝트 파일이 포함된 새 폴더가 만들어집니다.
Android 스튜디오에서 프로젝트 열기
- Android 스튜디오를 시작합니다.
- Welcome to Android Studio 창에서 Open을 클릭합니다.
참고: Android 스튜디오가 이미 열려 있는 경우 File > Open 메뉴 옵션을 대신 선택합니다.
- 파일 브라우저에서 압축 해제된 프로젝트 폴더가 있는 위치로 이동합니다(예: Downloads 폴더).
- 프로젝트 폴더를 더블클릭합니다.
- Android 스튜디오가 프로젝트를 열 때까지 기다립니다.
- Run 버튼 을 클릭하여 앱을 빌드하고 실행합니다. 예상대로 작동하는지 확인합니다.
2. 스타터 앱 개요
Tip Time 앱은 사용자에게 청구 금액을 입력하는 텍스트 입력과 팁 비율을 선택하는 라디오 버튼, 팁을 계산하는 버튼을 보여주는 화면 하나로 구성됩니다.
3. 계측 테스트 디렉터리 만들기
이 Codelab의 시작 코드는 완전히 작동하지만 테스트와 테스트 디렉터리가 모두 없습니다. 어떤 종류의 테스트든 작성하기 전에 계측 테스트를 위한 디렉터리를 추가해야 합니다. 시작 코드를 다운로드한 후 다음 단계를 따라 계측 테스트용 클래스를 추가합니다.
- 가장 쉬운 방법은 먼저 Android 뷰에서 Project 뷰로 전환하는 것입니다. 왼쪽 상단의 프로젝트 창에서 Android라는 드롭다운을 클릭하고 Project를 선택합니다.
- 이제 프로젝트 뷰가 다음과 같이 표시됩니다.
- 첫 번째 드롭다운을 클릭하고 app -> src로 드릴다운합니다.
- src를 마우스 오른쪽 버튼으로 클릭하고 New -> Directory를 선택합니다.
- 다음과 같은 창이 표시됩니다.
- androidTest/java를 선택합니다.
- 이제 프로젝트 구조에 androidTest 디렉터리가 표시됩니다.
- java 디렉터리를 마우스 오른쪽 버튼으로 클릭하고 New -> Package를 선택합니다.
- 결과 창이 다음과 같이 표시됩니다.
- 창에서 아래 텍스트를 입력하고 Return을 누릅니다.
com.example.tiptime
- 프로젝트 창이 다음과 같이 표시됩니다.
- 마지막으로 com.example.tiptime을 마우스 오른쪽 버튼으로 클릭하고 New -> Kotlin Class/File을 선택합니다.
- 결과 창에서
CalculatorTests
를 입력하고 드롭다운에서 Class를 선택한 후 Return을 누릅니다.
4. 첫 번째 계측 테스트 작성
이제 계측 테스트를 작성해 보겠습니다. 다음 단계에서는 20% 팁 기능을 테스트합니다.
- 방금 만든 파일을 열면 다음과 같이 표시됩니다.
package com.example.tiptime
class CalculatorTests {
}
- 계측 테스트에는 기기나 에뮬레이터에서 테스트를 실행할 수 있는 InstrumentationTestRunner가 필요합니다. 다른 여러 계측 실행기가 있지만 이 테스트에서는
AndroidJUnit4
테스트 실행기를 사용합니다. 테스트 실행기를 지정하려면 다음과 같이 클래스에 주석을 달아야 합니다.
@RunWith(AndroidJUnit4::class)
class CalculatorTests {
}
만일을 대비하여 다음의 가져오기가 필요합니다.
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.runner.RunWith
이제 모두 설정되었으므로 테스트 로직 작성을 시작할 수 있습니다.
- Tip Time 앱은 단일 활동
MainActivity
로 구성됩니다. 활동과 상호작용하려면 테스트 사례에서 먼저 활동을 실행해야 합니다.CalculatorTests
클래스 내부에 다음을 추가합니다.
@get:Rule()
val activity = ActivityScenarioRule(MainActivity::class.java)
ActivityScenarioRule
은 AndroidX 테스트 라이브러리에서 가져옵니다. 기기에 개발자가 지정한 활동을 실행하라고 지시합니다. @get:Rule
로 주석을 달아야 합니다. 이는 후속 규칙(이 경우 활동 실행)이 클래스의 모든 테스트 전에 실행되어야 한다고 지정합니다. 테스트 규칙은 테스트에 필수적인 도구이므로 결국 직접 작성하는 방법을 배우게 됩니다.
- 이제 테스트 로직 자체를 작성해야 합니다. 함수를 만들어
calculate_20_percent_tip()
이라고 하고@Test
로 주석을 답니다.
@Test
fun calculate_20_percent_tip() {
}
Espresso
이 과정에서는 주로 계측 테스트에 Espresso를 사용합니다. Espresso는 Android 스튜디오에서 Android 프로젝트를 만들 때 이러한 프로젝트에 사용할 수 있는 라이브러리로, 이를 사용해 개발자는 코드를 통해 UI 구성요소와 상호작용할 수 있습니다.
Android 스튜디오는 다양한 자동 완성 기능을 갖추고 있습니다. Espresso를 사용할 때 어려운 점 중 하나는 라이브러리를 가져오지 않으면 메서드가 자동 완성되지 않는다는 점입니다. 따라서 문서를 조사하지 않으면 Espresso에서 사용 가능한 메서드를 탐색하기 어려울 수 있습니다. 이러한 강의를 통해 테스트를 완료하는 데 필요한 메서드를 제공합니다.
먼저 Cost of Service 입력 텍스트 뷰에 청구 금액을 입력하는 코드를 작성해야 합니다. app -> src -> main -> res -> layout -> activity_main.xml로 이동하면 TextInputEditText
의 ID가 cost_of_service_edit_text
임을 나타냅니다. 나중에 테스트에 필요하므로 ID 이름을 복사합니다.
테스트 함수 구현
이제 테스트 클래스의 calculate_20_percent_tip()
함수에서 테스트 로직을 작성할 수 있습니다.
- 첫 번째 단계는
onView()
함수를 사용하여 상호작용할 UI 구성요소(이 경우에는TextInputEditText
)를 찾는 것입니다.onView()
함수는ViewMatcher
객체 매개변수를 사용합니다.ViewMatcher
는 기본적으로 특정 기준과 일치하는 UI 구성요소입니다. 이 경우에는 ID가R.id.cost_of_service_edit_text
인 구성요소입니다.
withId()
함수는 전달된 ID가 있는 UI 구성요소인 ViewMatcher
를 반환합니다. onView()
는 ViewInteraction
을 반환합니다. 이는 마치 기기를 직접 제어하는 것처럼 상호작용할 수 있는 객체입니다. 텍스트를 입력하려면 ViewInteraction
에서 perform()
을 호출합니다. 그러면 perform()
은 ViewAction
객체를 사용합니다. ViewAction
을 반환하는 메서드는 많이 있지만 지금은 typeText()
메서드를 사용합니다. activity_main.xml
에서 기본 팁 옵션이 20%임을 확인할 수 있으므로 현재로서는 선택할 팁 옵션을 지정하지 않아도 됩니다.
onView(withId(R.id.cost_of_service_edit_text))
.perform(typeText("50.00"))
그러고 나면 전체 명령어는 다음과 같이 표시됩니다.
onView(withId(R.id.cost_of_service_edit_text))
.perform(typeText("50.00"))
.perform(ViewActions.closeSoftKeyboard())
- 이제 텍스트가 입력되므로 테스트에서 Calculate 버튼을 클릭해야 합니다. 이를 위한 코드는 텍스트를 입력하는 데 사용한 것과 유사한 형식을 따릅니다. UI 구성요소가 다르므로
withId()
함수에 전달되는 ID 이름도 다릅니다. 그러나 이 접근 방식의 유일한 차이점은ViewAction
이 다르다는 점입니다.typeText()
대신click()
함수가 사용됩니다.
onView(withId(R.id.calculate_button))
.perform(click())
- 마지막으로 올바른 팁이 표시되었다고 어설션을 만들어야 합니다. 팁 금액은 $10.00일 것으로 예상됩니다. 이 테스트에서는 ID가
tip_result
인TextView
에 예상 팁 값이 문자열 형식으로 포함되어 있는지 확인합니다.
onView(withId(R.id.tip_result))
.check(matches(withText(containsString("$10.00"))))
메시지가 표시되면 다음 가져오기를 선택합니다.
import androidx.test.espresso.assertion.ViewAssertions.matches
import org.hamcrest.Matchers.containsString
여기서는 ViewAssertion
을 사용하는 check()
라는 다른 상호작용을 사용했습니다. ViewAssertion
을 UI 구성요소에 사용되는 특별한 Espresso 어설션으로 생각하면 됩니다. 어설션은 TextView
의 콘텐츠가 "$10.00"
문자열이 포함된 텍스트와 일치한다는 것입니다.
테스트를 실행하기 전에 가져오기와 코드가 올바른지 확인합니다. 다음과 같이 표시되어야 합니다. 가져오기의 순서가 다른 것은 괜찮습니다.
package com.example.tiptime
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.typeText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.hamcrest.Matchers.containsString
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class CalculatorTests {
@get:Rule()
val activity = ActivityScenarioRule(MainActivity::class.java)
@Test
fun calculate_20_percent_tip() {
onView(withId(R.id.cost_of_service_edit_text))
.perform(typeText("50.00"))
onView(withId(R.id.calculate_button)).perform(click())
onView(withId(R.id.tip_result))
.check(matches(withText(containsString("$10.00"))))
}
}
에뮬레이터를 사용하는 경우 에뮬레이터와 Android 스튜디오 창을 동시에 볼 수 있어야 합니다. 단위 테스트를 실행하는 같은 방식으로 테스트를 실행하고(함수 왼쪽에 있는 빨간색/녹색 화살표 버튼을 마우스 오른쪽 버튼으로 클릭하고 첫 번째 옵션을 선택) 어떤 결과가 나오는지 확인합니다.
누군가 앱 자체와 상호작용하는 것처럼 테스트가 실행되는 것을 확인할 수 있습니다.
5. 테스트 모음 확장
축하합니다. 첫 번째 계측 테스트를 완료했습니다.
테스트를 더 많이 해 보려면 다른 팁 비율을 테스트하는 함수를 추가하여 테스트 모음을 확장하면 됩니다. 위에서 작성한 함수와 같은 형식을 사용합니다. 유일하게 변경해야 하는 사항은 다른 비율 옵션을 선택하고 다른 예상 결과를 고려하도록 containsString()
에 전달된 값을 변경하는 코드를 작성하는 것입니다. 올림 옵션도 있습니다. onView(withId())
로 보여준 것처럼 ID로 구성요소를 찾아 클릭하여 올림 스위치를 전환할 수 있습니다.
6. 솔루션 코드
7. 요약
- Android 스튜디오는 프로젝트가 만들어질 때 필요한 테스트 클래스를 생성합니다. 그러나 테스트 클래스가 없는 프로젝트가 발생한 경우 직접 테스트 클래스를 만들면 됩니다.
- 테스트 규칙은 테스트 클래스의 모든 테스트 전에 실행됩니다.
- Espresso는 계측 테스트의 기본 구성요소입니다. Espresso를 통해 코드를 사용하여 UI 구성요소와 상호작용할 수 있습니다.
강의가 매우 길었습니다. 잘 마쳤다고 스스로 칭찬해 주세요.