Android 官方培训中文版:使用 Instrumentation 与 ActivityInstrumentationTestCase2 编写 UI 组件白盒测试

发布时间:2026/10/7 20:16:35
Android 官方培训中文版:使用 Instrumentation 与 ActivityInstrumentationTestCase2 编写 UI 组件白盒测试 文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载本文基于开源仓库《Android 官方培训课程中文版》中的 测试UI组件 一文整理扩展并对照同系列课程 建立测试环境、创建与执行测试用例、创建单元测试、创建功能测试 进行佐证。课程总入口见 测试你的Activity。Activity 是用户与 Android 应用交互的入口其内部承载着按钮、复选框、文本框、选框等各类 UI 组件。本文讲解如何在拥有被测应用源码的前提下利用 Android Instrumentation 框架为这些 UI 组件编写白盒测试验证按钮是否正确显示在屏幕上、TextView 初始是否隐藏、点击按钮后是否出现预期文本并在此基础上掌握ViewAsserts、TouchUtils、SmallTest/MediumTest/LargeTest等核心 API 与测试组织方式。读完本文你将能够为任意一个带 UI 的 Activity 建立一套可重复运行的界面行为测试用例并在开发周期中持续回归验证。一、白盒测试与黑盒测试本节方法的定位UI 测试通常分为两类白盒测试White-box testing测试者拥有被测应用程序的源码。本节所讲的 Instrumentation 框架正是适用于创建应用中 UI 部件的白盒测试。黑盒测试Black-box testing测试者无法得知应用源代码。这类测试通常用来验证应用如何与其他应用或与系统交互不在本节讨论范围之内。从仓库中可以看到本课程在 测试你的Activity 一节中明确将「测试 UI 组件」与「创建单元测试」「创建功能测试」并列单元测试见 创建单元测试使用ActivityUnitTestCase隔离单个 ActivityIntent 实际上不会发送给系统只校验载荷数据功能测试见 创建功能测试使用ActivityInstrumentationTestCase2配合ActivityMonitor验证多个 Activity 之间的交互UI 组件测试本文同样基于ActivityInstrumentationTestCase2聚焦于单一 Activity 内部控件的显示状态与点击行为。三者互补需要与系统通信、发送点击和键盘事件时选择ActivityInstrumentationTestCase2单元测试不适合测试与系统有复杂交互的 UI这类交互应交给本文所描述的 Instrumentation 测试来完成。二、用 Instrumentation 建立 UI 测试线程模型是关键当测试一个带 UI 的 Activity 时被测试的 Activity 运行在UI 线程上而测试程序运行在自己的进程、单独的线程内。这意味着测试程序可以获取UI 线程上的对象引用但如果测试程序尝试改变UI 线程对象的值会抛出WrongThreadException。为了安全地将Intent注入 Activity或在 UI 线程中执行测试方法应让测试类继承自ActivityInstrumentationTestCase2。该基类本身是ActivityTestCase的子类继承关系可对照 创建与执行测试用例 中的写法它封装了 Instrumentation 与目标 Activity 之间的交互保证测试可以安全地与 UI 通信。建立测试数据集Fixture为 UI 测试建立数据集时应在setUp()方法中指定touch mode触摸模式。把 touch mode 设为true可以防止执行测试方法时人为的 UI 操作获取到控件的焦点例如一个按钮因此触发它的点击监听器。关键约束是必须在调用getActivity()之前调用setActivityInitialTouchMode()否则设置不生效。示例对应原文档中ClickFunActivityTest.java的核心结构public class ClickFunActivityTest extends ActivityInstrumentationTestCase2 { ... Override protected void setUp() throws Exception { super.setUp(); setActivityInitialTouchMode(true); mClickFunActivity getActivity(); mClickMeButton (Button) mClickFunActivity .findViewById(R.id.launch_next_activity_button); mInfoTextView (TextView) mClickFunActivity.findViewById(R.id.info_text_view); } }这段代码遵循了 创建与执行测试用例 中总结的setUp()标准流程调用父类super.setUp()JUnit 的要求初始化测试数据集状态——定义保存测试数据与状态的实例变量通过getActivity()创建并保存被测 Activity 的引用获取 Activity 中要测试的 UI 组件findViewById引用。三、添加测试方法确认 UI 响应表现一个完整的 UI 测试应至少覆盖以下目标检验 Activity 启动时Button在正确布局位置显示检验TextView初始化时是隐藏的检验TextView在Button点击时显示预期的字符串。下面的小节逐一演示如何实现这些验证。1. 验证 Button 布局参数添加如下测试方法验证 Activity 中的按钮是否正确显示在屏幕上、宽高是否符合布局文件预期MediumTest public void testClickMeButton_layout() { final View decorView mClickFunActivity.getWindow().getDecorView(); ViewAsserts.assertOnScreen(decorView, mClickMeButton); final ViewGroup.LayoutParams layoutParams mClickMeButton.getLayoutParams(); assertNotNull(layoutParams); assertEquals(layoutParams.width, WindowManager.LayoutParams.MATCH_PARENT); assertEquals(layoutParams.height, WindowManager.LayoutParams.WRAP_CONTENT); }要点说明ViewAsserts.assertOnScreen()调用时传入根视图Root View以及期望呈现在屏幕上的视图作为参数。如果目标视图不在根视图中该方法会抛出AssertionFailedError否则测试通过。布局参数验证通过获取ViewGroup.LayoutParams对象的引用再用断言方法验证按钮的宽高属性值是否与预期一致此处为MATCH_PARENT×WRAP_CONTENT。MediumTest注解指定测试方法的归类与其执行时间相关详情见第五节。2. 验证 TextView 的布局参数验证TextView在 Activity 启动时最初处于隐藏状态MediumTest public void testInfoTextView_layout() { final View decorView mClickFunActivity.getWindow().getDecorView(); ViewAsserts.assertOnScreen(decorView, mInfoTextView); assertTrue(View.GONE mInfoTextView.getVisibility()); }这里通过getDecorView()方法获得 Activity 中**修饰视图Decor View**的引用。Decor View 在布局层级中是位于最上层的 ViewGroup一个FrameLayout因此用它作为assertOnScreen()的根视图基准最合适。注意隐藏状态的判断标准View.GONE表示视图不占布局空间且不可见若布局中用的是View.INVISIBLE则需断言View.INVISIBLE mInfoTextView.getVisibility()二者语义不同应依据实际布局文件选择。3. 验证按钮的行为验证点击按钮后 TextView 变得可见并显示预期的字符串MediumTest public void testClickMeButton_clickButtonAndExpectInfoText() { String expectedInfoText mClickFunActivity.getString(R.string.info_text); TouchUtils.clickView(this, mClickMeButton); assertTrue(View.VISIBLE mInfoTextView.getVisibility()); assertEquals(expectedInfoText, mInfoTextView.getText()); }要点说明TouchUtils.clickView()以编程方式点击按钮必须传递正在运行的测试用例的引用this和要操作的按钮引用。预期字符串从资源读取mClickFunActivity.getString(R.string.info_text)从strings.xml读取期望文本而不是在代码中硬编码。这一点与 创建与执行测试用例 中的建议一致——从资源文件读取预期字符串可以防止资源定义修改时影响测试效果。断言组合先验证可见性从GONE变为VISIBLE再验证文本内容assertEquals(expectedInfoText, mInfoTextView.getText())。注意TouchUtils辅助类提供与应用程序交互的方法可方便模拟触摸操作如模拟点击、轻敲或拖动屏幕上的 View。它的设计目的是将事件安全地从测试线程发送到 UI 线程。警告不要在 UI 线程直接调用TouchUtils方法也不要在任何标注了UIThread的测试方法中使用TouchUtils否则可能抛出错误线程异常WrongThreadException。四、应用测试注解按执行时间组织测试Instrumentation 测试框架内置了三类标准注解用于把测试方法归类到不同的测试组进而控制测试的组织与运行注解含义适用场景SmallTest该测试方法是小型测试的一部分只需要几毫秒就能完成的快速测试MediumTest该测试方法是中等测试的一部分运行 100 毫秒或更多、主要访问本地系统资源的测试LargeTest该测试方法是大型测试的一部分长时间运行、访问网络或其他外部资源的测试简单判定原则测试方法只需几毫秒则应标记为SmallTest长时间运行100 毫秒或更多的测试通常标记为MediumTest或LargeTest主要取决于测试是否访问网络或本地系统资源。本文三个 UI 测试示例均使用MediumTest因为点击交互、视图测量与布局绘制都需要一定执行时间。此外还可以创建自定义的测试注解来控制测试的组织和运行方式。测试注解体系基于java.lang.annotation.Annotation可按需扩展更细粒度的测试分组。五、把 UI 测试接入测试运行流程UI 测试本质上仍属于 Instrumentation 测试其构建与运行方式与普通 Activity 测试一致。参考同系列课程 建立测试环境IDE 方式Eclipse ADT右键点击测试类选择Run As Android JUnit Test在设备选择对话框中选择已连接并开启 USB 调试的设备然后在 JUnit 视图中查看通过、失败与错误结果。命令行方式Gradle确保gradle.build的defaultConfig中minSdkVersion为 8 或更高连接真机或开启模拟器后在项目目录执行./gradlew build connectedCheckconnectedCheck会连接设备运行所有 Instrumentation 测试包括本文所述的 UI 测试用例。注意本课程基于 Eclipse 与 ADT 插件编写你在实际开发中可以自由选用 IDE 或命令行工具。六、与单元测试、功能测试的边界对照为避免在测试选型时混淆这里对照同系列课程总结三条路径的差异维度单元测试功能测试UI 组件测试测试基类ActivityUnitTestCaseActivityInstrumentationTestCase2ActivityInstrumentationTestCase2被测 Activity需显式startActivity(intent, null, null)启动独立运行由框架启动可与系统通信由框架在 UI 线程启动UI 操作方式直接调用performClick()不可用TouchUtilsTouchUtils.clickView()等TouchUtils.clickView()等验证重点Intent 载荷、单个 Activity 内部状态Activity 之间的跳转与数据传递配合ActivityMonitor控件显示状态与点击行为适用场景快速、隔离、不依赖系统/网络跨组件协同工作单个界面的 UI 交互单元测试因为被测 Activity 是独立运行的不能使用TouchUtils库操作 UI需要直接调用View.performClick()而本文的 UI 测试与功能测试均可安全使用TouchUtils向 UI 线程派发事件。理解这层差异有助于为不同场景选择正确的测试基类。七、小结与完整示例本文以 测试UI组件 为主体完成了从线程模型、Fixture 建立、三类 UI 断言到测试注解组织、测试运行的完整闭环。核心要点可归纳为继承ActivityInstrumentationTestCase2让测试与 Activity 在不同线程运行但交互安全setUp()中先setActivityInitialTouchMode(true)再getActivity()防止误触发控件焦点与点击监听器用ViewAsserts.assertOnScreen(decorView, view)验证控件是否在屏幕内用ViewGroup.LayoutParams验证宽高用getVisibility()与getText()验证状态与内容用TouchUtils.clickView()模拟真实点击切勿在 UI 线程或UIThread方法中使用用SmallTest/MediumTest/LargeTest按执行时间组织测试。仓库中testing/activity-testing/目录完整收录了本课程的全部五篇文档建立测试环境、创建与执行测试用例、测试UI组件、创建单元测试、创建功能测试可作为搭建整套 Activity 测试体系的参考。原文档所引用的完整示例代码AndroidTestingFun.zip及ClickFunActivityTest.java位于 Android 官方培训材料中读者可结合本文代码块自行在本地测试工程中重建并运行验证。赞分享文档教程移动开发【免费下载链接】android-training-course-in-chineseAndroid官方培训课程中文版项目地址https://gitcode.com/gh_mirrors/an/android-training-course-in-chinese点击查看免费下载相关推荐Android 官方培训课程中文版创建 Activity 功能测试 —— 基于 ActivityInstrumentationTestCase2 与 ActivityMonitor 验证组件间协作Android 官方培训课程中文版创建 Activity 功能测试 —— 基于 ActivityInstrumentationTestCase2 与 Acti文档教程移动开发Android官方培训课程中文版使用 ActivityUnitTestCase 创建 Activity 单元测试Android官方培训课程中文版使用 ActivityUnitTestCase 创建 Activity 单元测试 本篇为《Android 官方培训课程中文版》文档教程移动开发Android 官方培训课程中文版使用 Fragment 建立灵活动态的 UIAndroid 官方培训课程中文版使用 Fragment 建立灵活动态的 UI 本篇技术指南基于《Android 官方培训课程中文版》开源仓库的 basics文档教程移动开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考