이 페이지에서는 핵심 권장사항과 그 이점을 비롯하여 Android 앱 테스트의 핵심 원칙을 간략하게 설명합니다.
테스트의 이점
테스트는 앱 개발 프로세스에서 빼놓을 수 없는 부분입니다. 앱 테스트를 일관되게 실행하여 앱을 공개적으로 출시하기 전에 앱의 정확성, 기능 동작, 사용성을 확인할 수 있습니다.
앱을 탐색하여 수동으로 앱을 테스트할 수 있습니다. 다양한 기기와 에뮬레이터를 사용하고, 시스템 언어를 변경하고, 모든 사용자 오류를 생성하거나 모든 사용자 흐름을 탐색할 수 있습니다.
하지만 수동 테스트는 확장성이 떨어지며 앱 동작의 회귀를 간과하기 쉽습니다. 자동 테스트는 테스트를 실행하는 도구를 사용하는 것으로, 개발 프로세스 초기에 더 빠르고 반복 가능하며 일반적으로 앱에 관한 더 실행 가능한 의견을 제공합니다.
Android의 테스트 유형
모바일 애플리케이션은 복잡하며 다양한 환경에서 잘 작동해야 합니다. 따라서 다양한 유형의 테스트가 있습니다.
제목
예를 들어 주제에 따라 다양한 유형의 테스트가 있습니다.
기능 테스트: 앱이 의도한 대로 작동하는가?
성능 테스트: 빠르고 효율적으로 작업을 수행하는가?
접근성 테스트: 접근성 서비스와 잘 작동하나요?
호환성 테스트: 모든 기기 및 API 수준에서 잘 작동하나요?
범위
테스트는 크기 또는 격리 수준에 따라 달라지기도 합니다.
단위 테스트 또는 소형 테스트는 메서드나 클래스 등 앱의 매우 작은 부분만 확인합니다.
엔드 투 엔드 테스트 또는 대형 테스트는 전체 화면이나 사용자 흐름과 같이 앱의 더 큰 부분을 동시에 확인합니다.
중형 테스트는 두 개 이상의 단위 간 통합을 확인합니다.
그림 1: 일반적인 애플리케이션의 테스트 범위
테스트를 분류하는 방법에는 여러 가지가 있습니다. 하지만 앱 개발자에게 가장 중요한 차이점은 테스트가 실행되는 위치입니다.
계측 테스트와 로컬 테스트 비교
Android 기기 또는 다른 컴퓨터에서 테스트를 실행할 수 있습니다.
계측 테스트는 실제 또는 에뮬레이트된 Android 기기에서 실행됩니다.
앱은 명령어를 삽입하고 상태를 읽는 테스트 앱과 함께 빌드되고 설치됩니다. 계측 테스트는 일반적으로 앱을 실행한 다음 앱과 상호작용하는 UI 테스트입니다.
로컬 테스트는 개발 머신이나 서버에서 실행되므로 호스트 측 테스트라고도 합니다. 일반적으로 작고 빠르며 테스트 중인 주제를 앱의 나머지 부분에서 격리합니다.
그림 2: 실행 위치에 따른 다양한 테스트 유형
모든 단위 테스트가 로컬인 것은 아니며 모든 엔드 투 엔드 테스트가 기기에서 실행되는 것은 아닙니다. 예를 들면 다음과 같습니다.
대규모 로컬 테스트: Robolectric과 같이 로컬로 실행되는 Android 시뮬레이터를 사용할 수 있습니다.
소규모 계측 테스트: 코드가 SQLite 데이터베이스와 같은 프레임워크 기능과 잘 작동하는지 확인할 수 있습니다. 여러 버전의 SQLite와의 통합을 확인하기 위해 여러 기기에서 이 테스트를 실행할 수 있습니다.
예
다음 스니펫은 요소를 클릭하고 다른 요소가 표시되는지 확인하는 계측 UI 테스트에서 UI와 상호작용하는 방법을 보여줍니다.
Espresso
// When the Continue button is clickedonView(withText("Continue")).perform(click())// Then the Welcome screen is displayedonView(withText("Welcome")).check(matches(isDisplayed()))
Compose UI
// When the Continue button is clickedcomposeTestRule.onNodeWithText("Continue").performClick()// Then the Welcome screen is displayedcomposeTestRule.onNodeWithText("Welcome").assertIsDisplayed()
이 스니펫은 ViewModel의 단위 테스트 (로컬, 호스트 측 테스트)의 일부를 보여줍니다.
// Given an instance of MyViewModelvalviewModel=MyViewModel(myFakeDataRepository)// When data is loadedviewModel.loadData()// Then it should be exposing dataassertTrue(viewModel.data!=null)
테스트 가능한 아키텍처
테스트 가능한 앱 아키텍처를 사용하면 코드가 격리된 상태로 다양한 부분을 쉽게 테스트할 수 있는 구조를 따릅니다. 테스트 가능한 아키텍처에는 가독성, 유지관리성, 확장성, 재사용성과 같은 다른 장점도 있습니다.
테스트할 수 없는 아키텍처는 다음을 생성합니다.
더 크고 느리고 불안정한 테스트 단위 테스트를 할 수 없는 클래스는 더 큰 통합 테스트나 UI 테스트로 다뤄야 할 수 있습니다.
다양한 시나리오를 테스트할 기회가 줄어듭니다. 테스트가 클수록 속도가 느려지므로 앱의 가능한 모든 상태를 테스트하는 것은 비현실적일 수 있습니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-08-08(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-08-08(UTC)"],[],[],null,["# Fundamentals of testing Android apps\n\nThis page outlines the core tenets of testing Android apps, including the\ncentral best practices and their benefits.\n\nBenefits of testing\n-------------------\n\nTesting is an integral part of the app development process. By running tests\nagainst your app consistently, you can verify your app's correctness, functional\nbehavior, and usability before you release it publicly.\n\nYou can *manually* test your app by navigating through it. You might use\ndifferent devices and emulators, change the system language, and try to generate\nevery user error or traverse every user flow.\n\nHowever, manual testing scales poorly, and it can be easy to overlook\nregressions in your app's behavior. *Automated testing* involves using tools\nthat perform tests for you, which is faster, more repeatable, and generally\ngives you more actionable feedback about your app earlier in the development\nprocess.\n\nTypes of tests in Android\n-------------------------\n\nMobile applications are complex and must work well in many environments. As\nsuch, there are many types of tests.\n\n### Subject\n\nFor example, there are different types of tests depending on the *subject*:\n\n- **Functional testing**: does my app do what it's supposed to?\n- **Performance testing**: does it do it quickly and efficiently?\n- **Accessibility testing**: does it work well with accessibility services?\n- **Compatibility testing**: does it work well on every device and API level?\n\n### Scope\n\nTests also vary depending on *size* , or *degree of isolation*:\n\n- **Unit tests** or **small tests** only verify a very small portion of the app, such as a method or class.\n- **End-to-end** tests or **big tests** verify larger parts of the app at the same time, such as a whole screen or user flow.\n- **Medium tests** are in between and check the **integration** between two or more units.\n\n**Figure 1**: Test scopes in a typical application.\n\nThere are many ways to classify tests. However, the most important distinction\nfor app developers is where tests run.\n\nInstrumented versus local tests\n-------------------------------\n\nYou can run tests on an Android device or on another computer:\n\n- **Instrumented tests** run on an Android device, either physical or emulated. The app is built and installed alongside a *test app* that injects commands and reads the state. Instrumented tests are usually UI tests, launching an app and then interacting with it.\n- **Local tests** execute on your development machine or a server, so they're also called *host-side tests*. They're usually small and fast, isolating the subject under test from the rest of the app.\n\n**Figure 2**: Different types of tests depending on where they run.\n\nNot all unit tests are local, and not all end-to-end tests run on a device. For\nexample:\n\n- **Big local test** : You can use an Android simulator that runs locally, such as [Robolectric](/training/testing/local-tests/robolectric).\n- **Small instrumented test**: You can verify that your code works well with a framework feature, such as a SQLite database. You might run this test on multiple devices to check the integration with multiple versions of SQLite.\n\n### Examples\n\nThe following snippets demonstrate how to interact with the UI in an\n*instrumented UI test* that clicks on an element and verifies that another\nelement is displayed. \n\n### Espresso\n\n // When the Continue button is clicked\n onView(withText(\"Continue\"))\n .perform(click())\n\n // Then the Welcome screen is displayed\n onView(withText(\"Welcome\"))\n .check(matches(isDisplayed()))\n\n### Compose UI\n\n // When the Continue button is clicked\n composeTestRule.onNodeWithText(\"Continue\").performClick()\n\n // Then the Welcome screen is displayed\n composeTestRule.onNodeWithText(\"Welcome\").assertIsDisplayed()\n\nThis snippet shows part of a *unit test* for a ViewModel (local, host-side\ntest): \n\n // Given an instance of MyViewModel\n val viewModel = MyViewModel(myFakeDataRepository)\n\n // When data is loaded\n viewModel.loadData()\n\n // Then it should be exposing data\n assertTrue(viewModel.data != null)\n\nTestable architecture\n---------------------\n\nWith a testable app architecture, the code follows a structure that allows you\nto easily test different parts of it in isolation. Testable architectures have\nother advantages, such as better readability, maintainability, scalability, and\nreusability.\n\nAn architecture that is *not testable* produces the following:\n\n- Bigger, slower, more flaky tests. Classes that can't be unit-tested might have to be covered by bigger integration tests or UI tests.\n- Fewer opportunities for testing different scenarios. Bigger tests are slower, so testing all possible states of an app might be unrealistic.\n\nTo learn more about architecture guidelines, see the [guide to app\narchitecture](/jetpack/guide).\n\n### Approaches to decoupling\n\nIf you can extract part of a function, class, or module from the rest, testing\nit is easier, and more effective. This practice is known as decoupling, and it\nis the concept most important to testable architecture.\n\nCommon decoupling techniques include the following:\n\n- Split an app into *layers* such as Presentation, Domain, and Data. You can also split an app into *modules*, one per feature.\n- Avoid adding logic to entities that have large dependencies, such as activities and fragments. Use these classes as entry points to the framework and move *UI and business logic* elsewhere, such as to a Composable, ViewModel, or domain layer.\n- Avoid direct *framework dependencies* in classes containing business logic. For example, [don't use Android Contexts in ViewModels](https://medium.com/androiddevelopers/locale-changes-and-the-androidviewmodel-antipattern-84eb677660d9).\n- Make dependencies easy to *replace* . For example, use [interfaces](https://en.wikipedia.org/wiki/Interface_segregation_principle) instead of concrete implementations. Use [Dependency injection](/training/dependency-injection) even if you don't use a DI framework.\n\nNext steps\n----------\n\nNow that you know why you should test and the two main types of tests, you can\nread [What to test](/training/testing/fundamentals/what-to-test) or learn about [Testing strategies](/training/testing/fundamentals/strategies)\n\nAlternatively, if you want to create your first test and learn by doing, check\nout the [Testing codelabs](/codelabs/advanced-android-kotlin-training-testing-basics)."]]