
示例工程教程【免费下载链接】cw-omnibusSource code to omnibus edition of _The Busy Coders Guide to Android Development_项目地址https://gitcode.com/gh_mirrors/cw/cw-omnibus点击查看免费下载本文基于 cw-omnibus 开源仓库中的 Testing/Coverage 示例应用讲解如何在 Android instrumentation 测试instrumented tests上启用代码覆盖率报告。该示例来自The Busy Coders Guide to Android Development中关于测试覆盖率的章节通过一个Action Bar Fragment Demo应用与一组 JUnit4 风格的 instrumentation 测试演示了从 Gradle 配置到报告生成的完整链路。读完本文你将掌握testCoverageEnabled开关的配置方法、覆盖率报告任务的执行方式以及如何从源码层面理解覆盖率统计的作用范围。示例项目概览用最小的应用讲清覆盖率配置Testing/Coverage 目录下是一个标准的 Android Studio 单模块项目其结构如下Testing/Coverage/ ├── app/ │ ├── build.gradle # 覆盖率开关所在位置 │ └── src/ │ ├── androidTest/ # instrumentation 测试源码 │ │ └── java/com/commonsware/android/abf/test/ │ └── main/ # 应用主代码与资源 ├── gradle/wrapper/ ├── proguard-project.txt ├── project.properties └── settings.gradle被测应用本体是一个展示 Action Bar Fragment 的列表应用ActionBarFragmentActivity在onCreate中通过 FragmentManager 向内容区添加一个ActionBarFragment见 ActionBarFragmentActivity.java。ActionBarFragment继承自ListFragment内置了 25 个单词组成的列表数据并提供菜单项用于重置列表见 ActionBarFragment.java。这个应用本身并不复杂——它的价值在于作为被测试对象为覆盖率报告提供真实的代码路径。项目配置信息方面project.properties声明了targetandroid-19的旧版构建目标而实际的app/build.gradle则采用现代 Gradle DSLcompileSdkVersion 27、minSdkVersion 15、targetSdkVersion 27。这些配置差异从侧面说明该示例经历了多次迁移但其核心——覆盖率配置——始终保持一致。核心开关testCoverageEnabled与 debug 构建类型覆盖率功能在 app/build.gradle 中仅通过一行配置开启apply plugin: com.android.application dependencies { implementation com.android.support:support-fragment:27.0.2 androidTestImplementation com.android.support.test:rules:1.0.1 } android { compileSdkVersion 27 buildToolsVersion 27.0.3 defaultConfig { minSdkVersion 15 targetSdkVersion 27 testApplicationId com.commonsware.android.gradle.hello.test testInstrumentationRunner android.support.test.runner.AndroidJUnitRunner } buildTypes { debug { testCoverageEnabled true } } }几个值得注意的配置点testCoverageEnabled true这是 Android Gradle Plugin 提供的覆盖率开关必须写在buildTypes的某个构建类型下。这里配置在debug类型上意味着只有 debug 构建会携带覆盖率插桩。从源码结构看覆盖率插桩由 Android Gradle Plugin 在编译期注入历史上基于 Emma后续版本则接入 JaCoCo 体系它会在每个方法入口/出口埋入探针运行时记录哪些行、哪些分支被执行。testInstrumentationRunner指定android.support.test.runner.AndroidJUnitRunner这是 instrumentation 测试的入口 runner覆盖率探针数据的收集正是由测试运行过程触发的。androidTestImplementation com.android.support.test:rules:1.0.1提供ActivityTestRule等测试基础设施见后文DemoActivityRuleTest。testApplicationId测试 APK 的独立包名。这里配置为com.commonsware.android.gradle.hello.test与主应用包名com.commonsware.android.abf见 AndroidManifest.xml不同这也是 Android instrumentation 测试的惯例——测试以独立 APK 的形式安装并驱动被测应用。提示由于仓库未包含gradlew及其 JAR见仓库根目录 README.markdown 中的安全说明从命令行构建时需要使用本地安装的 Gradle。运行测试并生成覆盖率报告配置完成后覆盖率报告的生成由 Gradle 提供的内置任务驱动。针对本例核心命令为gradle createDebugCoverageReportcreateDebugCoverageReport任务会依次完成安装被测 debug APK 与测试 APK → 运行全部 instrumentation 测试 → 汇总覆盖率数据 → 输出 HTML、XML 等格式的报告。报告默认输出到app/build/reports/coverage/debug/其中index.html是可交互浏览的报告首页展示了总览overall coverage行覆盖率line coverage与分支覆盖率branch coverage的百分比汇总包与类粒度明细逐包、逐类下钻可以定位到具体行是否被测试执行到源码视图点击某个类即可看到行号级的覆盖标注绿色已覆盖红色未覆盖。需要说明的是这份报告统计的是被测应用进程的代码执行情况而不是测试代码自身的覆盖。以本例而言报告关注的是ActionBarFragmentActivity、ActionBarFragment及其依赖的 View 层代码被 instrumentation 测试触发了多少。测试套件源码剖析覆盖率报告背后的测试依据覆盖率数字本身没有意义支撑它的是测试套件实际执行了哪些代码路径。该示例在androidTest目录下准备了四个测试类覆盖了不同层级的测试场景1.DemoActivityTest传统 Activity 测试 三种交互方式DemoActivityTest.java 继承自ActivityInstrumentationTestCase2ActionBarFragmentActivity是 JUnit3 风格与 JUnit4 注解混用的典型RunWith(AndroidJUnit4.class) public class DemoActivityTest extends ActivityInstrumentationTestCase2ActionBarFragmentActivity { private ListView listnull; public DemoActivityTest() { super(ActionBarFragmentActivity.class); } Before Override public void setUp() throws Exception { super.setUp(); injectInstrumentation(InstrumentationRegistry.getInstrumentation()); setActivityInitialTouchMode(false); ActionBarFragmentActivity activitygetActivity(); list(ListView)activity.findViewById(android.R.id.list); } ... }其三个Test方法分别演示了三种不同的 UI 验证手段每一种都会驱动被测应用的不同代码路径从而影响覆盖率结果listCount()直接断言ListView的 adapter 条目数为 25覆盖了ActionBarFragment.initAdapter()的数据组装逻辑keyEvents()通过sendKeys(4*DPAD_DOWN)发送按键事件断言选中项位置覆盖了 ListView 的焦点/选择处理路径touchEvents()通过TouchUtils.scrollToBottom(...)执行触摸滚动再断言getLastVisiblePosition()为 24覆盖了列表滚动的绘制与布局逻辑。2.DemoActivityRuleTest基于 Rule 的现代写法DemoActivityRuleTest.java 展示了更现代的 JUnit4 Rule 风格——用ActivityTestRule代替setUp()/getActivity()的样板代码RunWith(AndroidJUnit4.class) public class DemoActivityRuleTest { private ListView listnull; Rule public final ActivityTestRuleActionBarFragmentActivity main new ActivityTestRule(ActionBarFragmentActivity.class, true); Before public void init() { list(ListView)main.getActivity().findViewById(android.R.id.list); } Test public void listCount() { Assert.assertEquals(25, list.getAdapter().getCount()); } }ActivityTestRule(ActionBarFragmentActivity.class, true)中的第二个参数initialTouchMode为true表示启动 Activity 时关闭触摸模式让按键事件可正常派发。这与DemoActivityTest中手动调用setActivityInitialTouchMode(false)的效果一致——可见两种测试范式解决的是同一个问题。3.DemoContextTest脱离 Activity 的布局测试DemoContextTest.java 演示了不依赖完整 Activity、直接用LayoutInflater加载布局的测试方式Before public void init() { InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { Override public void run() { LayoutInflater inflaterLayoutInflater .from(InstrumentationRegistry.getTargetContext()); rootinflater.inflate(R.layout.add, null); } }); root.measure(800, 480); root.layout(0, 0, 800, 480); fieldroot.findViewById(R.id.title); }这里加载的 add.xml 是一个独立的EditText布局菜单项Add的 actionLayout。测试通过runOnMainSync保证布局操作发生在主线程随后手动执行measure/layout完成视图的测量与排布再断言EditText存在且位于左上角getTop()0 getLeft()0。这类测试能有效覆盖纯布局膨胀 视图定位的代码路径而这些路径在常规 UI 交互测试中往往被间接触发或漏掉。4.SillyTestJUnit4 生命周期骨架SillyTest.java 是一个故意设计得很简单的测试类其价值在于完整展示 JUnit4 的四个生命周期钩子BeforeClassstatic整个测试类运行前执行一次适合一次性初始化Before每个测试方法前执行After每个测试方法后执行AfterClassstatic整个测试类运行结束后执行一次适合资源清理。唯一的Test方法thisIsReallySilly断言1 1配上一个幽默的失败消息bit got flipped by cosmic rays。这个类虽然是占位型测试却让RunWith(AndroidJUnit4.class)驱动的整个测试生命周期可被完整观测——对于理解 instrumentation 测试的执行模型很有帮助。覆盖率报告的价值与局限结合本示例可以总结出覆盖率报告在 Android 项目中的实际定位定位测试盲区将覆盖率数据与测试类逐一对照可以判断ActionBarFragment的菜单逻辑onCreateOptionsMenu、onOptionsItemSelected中的 reset 分支是否被测试命中。从当前测试套件看四个测试类主要覆盖了列表初始化、布局膨胀与基础交互而菜单的 reset 分支并没有对应的测试用例——这正是覆盖率报告能帮助发现的典型盲区。量化回归防护把行覆盖率作为 CI 门禁指标可以防止新增代码裸奔上线。认识其局限覆盖率只回答代码是否被执行不回答执行是否正确同时 instrumentation 测试的覆盖率统计发生在被测应用进程内异步回调、多进程组件如android:process指定的 Service需要单独考量。从本示例的实现来看报告生成依赖测试完整跑完因此测试稳定性会直接影响覆盖率数据质量。延伸阅读本示例在仓库根 README.markdown 的 Samples 列表中登记为Testing/Coverage属于书中测试覆盖率章节的配套源码同目录下的 Testing/JUnit4 示例聚焦 JUnit4 测试本身与本文的DemoActivityRuleTest、SillyTest可以互相印证仓库中所有源码均遵循 Apache 2.0 许可可在阅读书章节的同时自由查看、运行和修改这些示例用于学习。赞分享示例工程教程【免费下载链接】cw-omnibusSource code to omnibus edition of _The Busy Coders Guide to Android Development_项目地址https://gitcode.com/gh_mirrors/cw/cw-omnibus点击查看免费下载相关推荐cw-omnibus 实战解析FauxSender 示例如何在 Android 中实现 ACTION_SEND 分享接收端cw omnibus 实战解析FauxSender 示例如何在 Android 中实现 ACTION_SEND 分享接收端 本文以开源仓库 cw omnibu示例工程教程cw-omnibus 全屏模式示例解读用 SYSTEM_UI_FLAG 接管 Android 屏幕显示cw omnibus 全屏模式示例解读用 SYSTEM_UI_FLAG 接管 Android 屏幕显示 本文围绕《The Busy Coders Guide示例工程教程Android 7.0 Network Security Configuration 实战cw-omnibus CA 示例的信任锚点、证书固定与调试覆盖Android 7.0 Network Security Configuration 实战cw omnibus CA 示例的信任锚点、证书固定与调试覆盖 本文示例工程教程上一篇Seafile性能监控工具自定义指标与可视化面板下一篇突破监控瓶颈Thanos与CI/CD无缝集成实践指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考