Android 应用测试基础

本页面概述了测试 Android 应用的核心原则,包括主要的最佳实践及其优势。

测试的优势

测试是应用开发过程中不可或缺的一部分。通过持续对应用运行测试,您可以在公开发布应用之前验证其正确性、功能行为和可用性。

您可以通过在应用中导航来手动测试您的应用。您可能会使用不同的设备和模拟器,更改系统语言,并尝试生成每个用户错误或遍历每个用户流程。

然而,手动测试的可伸缩性较差,并且很容易忽略应用行为中的回归。自动化测试涉及使用工具为您执行测试,这种方式更快、可重复性更高,并且通常能在开发过程的早期为您提供关于应用的更多可操作反馈。

Android 中的测试类型

移动应用复杂且必须在多种环境下良好运行。因此,存在多种类型的测试。

主题

例如,根据主题的不同,存在不同类型的测试

  • 功能测试:我的应用是否按预期运行?
  • 性能测试:它是否快速高效地运行?
  • 无障碍测试:它是否与无障碍服务良好配合?
  • 兼容性测试:它是否在每台设备和每个 API 级别上都良好运行?

范围

测试也因大小隔离程度而异

  • 单元测试小型测试仅验证应用的一小部分,例如方法或类。
  • 端到端测试大型测试同时验证应用的更大组成部分,例如整个屏幕或用户流程。
  • 中型测试介于两者之间,检查两个或更多单元之间的集成
Tests can be either small, medium, or big.
图 1:典型应用中的测试范围。

测试的分类方法有很多种。然而,对于应用开发者而言,最重要的区别在于测试运行的位置。

插桩测试与本地测试

您可以在 Android 设备上或在另一台计算机上运行测试

  • 插桩测试在 Android 设备(物理设备或模拟设备)上运行。应用与一个测试应用一起构建和安装,该测试应用注入命令并读取状态。插桩测试通常是 UI 测试,用于启动应用然后与其交互。
  • 本地测试在您的开发机器或服务器上执行,因此也称为主机端测试。它们通常小巧且快速,将测试对象与应用的其他部分隔离开来。
Tests can run as instrumented tests on a device, or local tests on your development machine.
图 2:根据运行位置划分的不同测试类型。

并非所有单元测试都是本地的,也并非所有端到端测试都在设备上运行。例如

  • 大型本地测试:您可以使用在本地运行的 Android 模拟器,例如 Robolectric
  • 小型插桩测试:您可以验证您的代码是否与框架功能(例如 SQLite 数据库)良好配合。您可以在多台设备上运行此测试,以检查与多个 SQLite 版本的集成情况。

示例

以下代码段演示了在插桩 UI 测试中如何与 UI 交互,该测试点击某个元素并验证是否显示了另一个元素。

Espresso

// When the Continue button is clicked
onView(withText("Continue"))
    .perform(click())

// Then the Welcome screen is displayed
onView(withText("Welcome"))
    .check(matches(isDisplayed()))

Compose UI

// When the Continue button is clicked
composeTestRule.onNodeWithText("Continue").performClick()

// Then the Welcome screen is displayed
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()

此代码段展示了 ViewModel 的单元测试的一部分(本地、主机端测试)

// Given an instance of MyViewModel
val viewModel = MyViewModel(myFakeDataRepository)

// When data is loaded
viewModel.loadData()

// Then it should be exposing data
assertTrue(viewModel.data != null)

可测试架构

采用可测试的应用架构,代码遵循一种结构,让您可以轻松地隔离测试其不同部分。可测试架构还具有其他优势,例如更好的可读性、可维护性、可伸缩性和可重用性。

不可测试的架构会产生以下问题

  • 更大、更慢、更不稳定的测试。无法进行单元测试的类可能需要由更大的集成测试或 UI 测试来覆盖。
  • 测试不同场景的机会更少。大型测试速度较慢,因此测试应用的所有可能状态可能不切实际。

如需详细了解架构指南,请参阅应用架构指南

解耦方法

如果您可以从其余部分中提取函数、类或模块的一部分,则测试它会更容易、更有效。这种做法称为解耦,它是可测试架构中最重要的概念。

常见的解耦技术包括以下几种

  • 将应用拆分为,例如表示层、领域层和数据层。您还可以将应用拆分为模块,每个功能一个模块。
  • 避免向具有大量依赖项的实体(例如 Activity 和 Fragment)添加逻辑。将这些类用作框架的入口点,并将界面和业务逻辑移到其他地方,例如 Composable、ViewModel 或领域层。
  • 避免在包含业务逻辑的类中直接依赖框架。例如,不要在 ViewModel 中使用 Android Context
  • 使依赖项易于替换。例如,使用接口而不是具体实现。即使您不使用 DI 框架,也要使用依赖注入

后续步骤

现在您已经了解了为什么要测试以及两种主要测试类型,您可以阅读要测试什么或了解测试策略

或者,如果您想创建您的第一个测试并通过实践学习,请查看测试 Codelab