// 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)
[null,null,["最后更新时间 (UTC):2025-08-08。"],[],[],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)."]]