【免费下载链接】qualitymatters
Android Development Culture
QualityMatters 是一个展示 Android 开发文化的示例 App,它的功能(UI)测试是整套质量体系中最贴近用户的一层:用 Espresso 编写 UI 测试,配合 Screen 架构封装界面操作、MockWebServer 模拟真实后端,从而打造稳定、零碎片的可靠功能测试。这些测试全部位于app/src/functionalTests目录下,运行在连接的模拟器或真机上,从用户视角验证 App 是否真的"好用"。
为什么 Espresso 功能测试容易"碎片化"?
功能(UI)测试最大的敌人不是写不出来,而是"不稳定"(Flaky):
- 异步时序问题:网络请求没回来就去断言,断言失败;
- 依赖真实后端:数据随线上环境变化,测试结果随机;
- UI 操作散落各处:
onView().perform(click())直接写在测试方法里,界面一改就要修一堆测试。
QualityMatters 用三层结构应对这些难题。先明确它在测试体系中的位置(详见 README.md 的 "Tests" 章节):
| 层级 | 运行环境 | 检查内容 |
|---|---|---|
单元测试src/unitTests | JVM | 单个类的隔离行为 |
集成测试src/integrationTests | JVM(Robolectric) | HTTP + REST + JSON + RxJava 的组合行为 |
功能测试src/functionalTests | 模拟器 / 真机 | 用户视角的 UI 行为 |
各文件的职责一目了然:
- QualityMattersFunctionalTestsRunner.java:自定义测试运行器
- QualityMattersFunctionalTestApp.java:测试专用 Application
- ItemsScreen.java:Screen 架构核心
- ItemsTest.java:全部功能测试用例
- MockWebServerRule.java:模拟服务器的 JUnit Rule
- AsyncJobsObserverRule.java:消除异步碎片的 IdlingResource
Screen 架构:把"点谁、看谁"封装成语义化方法
Screen 架构(Screen Pattern)的核心思想:每个界面用一个 Screen 类封装,测试代码只说"用户看到了什么",不说"哪个 View 被点了"。
ItemsScreen.java 中,每个方法都做一件事并return this,让测试可以流式串联,读起来就像剧本:
shouldDisplayTitle(title)—— 标题栏显示指定文案shouldDisplayItemWithTitle(title)—— 列表中存在指定标题shouldDisplayTryAgainButton()/clickOnTryAgainButton()—— 错误按钮显示 / 点击重试shouldDisplayExpectedAmountOfItems(count)—— 列表条目数等于预期shouldNotDisplayItems()—— 列表不可见
再看 ItemsTest.java 里最复杂的用例shouldDisplayErrorUiThenReloadResultSuccessfully(第 95~119 行),整个"失败→重试→成功"的用户流程一气呵成:
显示错误文案 → 显示重试按钮 → 列表不可见 → 点击重试 → 显示 3 个条目 → 逐条校验标题与描述
好处很直接:当某个控件的布局或id变化时,只需要改 Screen 类,所有测试用例不用动;同时测试方法不再出现任何onView/withId,非核心同学也能看懂测试在验证什么。
MockWebServer:把"后端"变成可控的本地服务器
功能测试要覆盖"数据加载成功"、"接口 500 显示错误页"、"重试后成功"等多种场景,依赖真实后端既慢又不可控。MockWebServer 是一个本地 HTTP 服务器,用enqueue()按顺序排队返回响应。
项目用一个自定义 JUnit Rule 托管它——MockWebServerRule.java 的工作流程:
- 检测测试方法上的 @NeedsMockWebServer 注解,没有就直接执行测试;
- 启动 MockWebServer,并通过 ChangeableBaseUrl.java 把 App 的 API 基地址指向本地端口——这个
ChangeableBaseUrl正是主代码"为可测试性而设计"的产物; - 反射调用
setupMethod指定的方法,向服务器排队响应; - 无论测试成败,
finally中shutdown(),保证下一个测试拿到干净的服务器。
一个精巧的细节:setupMethod参数存在,是因为 App 的ActivityTestRule会在测试方法之前就把MainActivity拉起来、请求已发出。响应必须在服务器"开始之前"入队,所以用注解 + 反射把数据准备提前。例如shouldDisplayErrorUiThenReloadResultSuccessfully对应的 setup 方法先入队一个HTTP/1.1 500,再入队 3 条正常数据——恰好对应"先失败、点后重试才成功"的剧本。
消除异步碎片:AsyncJobsObserverRule 的 IdlingResource 技巧
这是"零碎片"最关键的一环。App 主代码内置了一个 AsyncJobsObserver 接口,能实时查询当前正在运行的异步任务数;功能测试用它构建 IdlingResource:
isIdleNow():正在运行的异步任务数为 0 时返回true,Espresso 才会继续执行断言;registerIdleTransitionCallback():监听任务数归零的时机,主动通知 Espresso 恢复——避免 Espresso 反复轮询。
效果:Espresso 会在"接口还没回来"时自动等待,而不是提前断言失败。不需要任何Thread.sleep。
三个 Rule 用RuleChain串起精确的执行顺序(见 ItemsTest.java 第 27~31 行):
RuleChain.emptyRuleChain() .around(new MockWebServerRule(this)) // 先起服务器、入队响应 .around(new AsyncJobsObserverRule()) // 再注册空闲感知 .around(new ActivityTestRule<>(MainActivity.class)) // 最后启动 Activity顺序很讲究:服务器必须最早启动,这样ActivityTestRule拉起页面触发的第一次网络请求,就能立刻命中 Mock 数据。
自定义 Runner 与测试专用 Application:测试不留脏数据
QualityMattersFunctionalTestsRunner.java 继承AndroidJUnitRunner,重写newApplication()用 QualityMattersFunctionalTestApp.java 替换真实 Application。测试 App 借助 Dagger 把AnalyticsModel换成"打 LogCat"的版本——功能测试期间既不上报脏数据到真实统计平台,又能直接在 LogCat 里看到埋点调用,顺带验证了 Analytics 的初始化时序。
此外还有两个小工具提升体验:
- ViewAssertions.java:自定义断言
recyclerViewShouldHaveItemsCount,校验条目数量时失败信息直接给出"实际 N 条,期望 M 条"; - ViewActions.java:提供
noOp()空操作,配合actionOnItem精确定位"列表中存在某文案的条目"而不真正执行点击; - TestUtils.java:一行拿到测试中的
QualityMattersApp实例,便于访问组件依赖。
功能测试可靠性要点清单
- Screen 架构:界面操作收敛到 Screen 类,测试只保留语义化断言链;
- MockWebServer + ChangeableBaseUrl:后端完全可控,成功 / 500 / 重试剧本随意编排,测试间互不污染;
- IdlingResource:基于真实的异步任务计数代替
Thread.sleep,从根上消除时序碎片; - RuleChain 管理初始化顺序:服务器 → 空闲感知 → Activity,各司其职;
- 自定义 Runner 替换依赖:Analytics 等外部依赖换成 Log 版本,测试环境干净无脏数据;
- 自定义 Matcher / ViewAction / ViewAssertion:把"条目数"这类通用校验沉淀为可复用工具。
整套功能测试全部位于app/src/functionalTests,通过 Instrumentation API 运行在连接的模拟器 / 真机上。配合 README.md 中介绍的单元测试与集成测试,QualityMatters 用"三层测试 + 可切换后端 + 全局异步观测 + Screen 语义封装"的组合拳,让 Espresso UI 测试真正做到了稳定、可读、零碎片——这正是它值得借鉴的功能测试范式。
【免费下载链接】qualitymatters
Android Development Culture
相关推荐
Detox-Native 源码级解析:用 DetoxViewActions 打造稳定可靠的 Espresso UI 测试
Detox Native 源码级解析:用 DetoxViewActions 打造稳定可靠的 Espresso UI 测试 Detox Native 是 Deto
测试移动开发质量保障开发工具OkGo单元测试框架:MockWebServer与Espresso结合
OkGo单元测试框架:MockWebServer与Espresso结合 单元测试现状分析 OkGo作为基于OkHttp的网络请求框架,其核心功能包括RESTfu
后端移动开发MyBookshelf自动化测试:Espresso UI测试
MyBookshelf自动化测试:Espresso UI测试 你还在手动测试MyBookshelf的每个界面交互吗?随着应用功能日益复杂,重复的手动测试不仅耗时
移动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考