☰
QualityMatters Espresso UI 测试:Screen 架构 + MockWebServer 打造零碎片的可靠功能测试
2026/10/11 1:28:47 网站建设 项目流程

【免费下载链接】qualitymatters

Android Development Culture

项目地址:https://gitcode.com/gh_mirrors/qu/qualitymatters
点击查看免费下载

QualityMatters 是一个展示 Android 开发文化的示例 App,它的功能(UI)测试是整套质量体系中最贴近用户的一层:用 Espresso 编写 UI 测试,配合 Screen 架构封装界面操作、MockWebServer 模拟真实后端,从而打造稳定、零碎片的可靠功能测试。这些测试全部位于app/src/functionalTests目录下,运行在连接的模拟器或真机上,从用户视角验证 App 是否真的"好用"。

为什么 Espresso 功能测试容易"碎片化"?

功能(UI)测试最大的敌人不是写不出来,而是"不稳定"(Flaky):

  • 异步时序问题:网络请求没回来就去断言,断言失败;
  • 依赖真实后端:数据随线上环境变化,测试结果随机;
  • UI 操作散落各处:onView().perform(click())直接写在测试方法里,界面一改就要修一堆测试。

QualityMatters 用三层结构应对这些难题。先明确它在测试体系中的位置(详见 README.md 的 "Tests" 章节):

层级运行环境检查内容
单元测试src/unitTestsJVM单个类的隔离行为
集成测试src/integrationTestsJVM(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 的工作流程:

  1. 检测测试方法上的 @NeedsMockWebServer 注解,没有就直接执行测试;
  2. 启动 MockWebServer,并通过 ChangeableBaseUrl.java 把 App 的 API 基地址指向本地端口——这个ChangeableBaseUrl正是主代码"为可测试性而设计"的产物;
  3. 反射调用setupMethod指定的方法,向服务器排队响应;
  4. 无论测试成败,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实例,便于访问组件依赖。

功能测试可靠性要点清单

  1. Screen 架构:界面操作收敛到 Screen 类,测试只保留语义化断言链;
  2. MockWebServer + ChangeableBaseUrl:后端完全可控,成功 / 500 / 重试剧本随意编排,测试间互不污染;
  3. IdlingResource:基于真实的异步任务计数代替Thread.sleep,从根上消除时序碎片;
  4. RuleChain 管理初始化顺序:服务器 → 空闲感知 → Activity,各司其职;
  5. 自定义 Runner 替换依赖:Analytics 等外部依赖换成 Log 版本,测试环境干净无脏数据;
  6. 自定义 Matcher / ViewAction / ViewAssertion:把"条目数"这类通用校验沉淀为可复用工具。

整套功能测试全部位于app/src/functionalTests,通过 Instrumentation API 运行在连接的模拟器 / 真机上。配合 README.md 中介绍的单元测试与集成测试,QualityMatters 用"三层测试 + 可切换后端 + 全局异步观测 + Screen 语义封装"的组合拳,让 Espresso UI 测试真正做到了稳定、可读、零碎片——这正是它值得借鉴的功能测试范式。

【免费下载链接】qualitymatters

Android Development Culture

项目地址:https://gitcode.com/gh_mirrors/qu/qualitymatters
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询