移动测试基础 [腾讯 TMQ] 当 Espresso 遇见 Android 单元测试

匿名 · 2017年08月21日 · 1937 次阅读

引言

在 Android 单元测试中,不依赖 Android 环境的可以使用 Junit。如果依赖 Android 环境,但是没有 UI 相关或者 UI 比较简单(如点击按钮)的单元测试可以使用开源库 Robolectric 解决依赖问题,使测试运行在 JVM 上,而非模拟器上,大大提高测试运行效率。

但是如果测试 UI 相关比较复杂的代码,又可以如何进行测试呢?

Activity& Espresso #

Activity 是承载 UI 控件的 Android 基本组件,Espresso 则是可操作 Activity 的 Google 原生 UI 自动化框架。

Espresso 特点有写法简单易入手,不可跨进程等(跨进程可使用 Uiautomator),学习参考https://google.github.io/android-testing-support-library/docs/espresso/index.html

工程中使用 Espresso 实现自动化测试只需要三步:

1、添加依赖:

androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'

androidTestCompile'com.android.support.test🏃0.5'

2、build.gradle 中 android.defaultConfig 配置:

testInstrumentationRunner"android.support.test.runner.AndroidJUnitRunner"

3、写好 case,进入工程主目录下执行 gradlew connectedAndroidTest。

测试对象

如果项目是组件化开发的架构,将各个同类功能的代码整合在一个组件中,以便整体打包,便于维护,模块解耦合,持续构建单元测试等,可以减少底层修改导致上层错误的风险。

因此,UI 控件库也作为一个单独的组件,比如时间选择器、标签组、数字选择器、带删除的输入框等等。

本文以控件时间选择器 TimePicker 作为测试对象来分析。

方案落地

想对复杂 UI 控件的代码进行单元测试,设计了如下方案。

1、将 UI 控件放入 Activity(xml 中配置);

2、添加一个输入框(也可用 Spinner)和按钮用来提交命令,不同的命令控制 UI 控件调用不同的函数,Activity 制作完成;

3、使用 Espresso 进行自动化操作输入命令和提交,并检查结果。

以上,UI 控件执行了初始化代码及各函数代码,达到单元测试的目的。

那么问题来了,为何不用 Espresso 直接获取 UI 控件对象进行函数调用呢?因为 Android 更改 UI 只能在 UI 线程中进行,所以改变控件属性的代码只能写在 Activity 的代码中,而不是 Espresso 的测试代码中。

否则会报错: Only
the original thread that created a view hierarchy cantouch its views.

Activity 制作

由方案步骤 1 与 2 可知,需要制作一个 Activity。

先看看带 TimePicker 和命令输入框的 Activity 实际效果:

时间选择器 TimePicker 的 class 文件的类结构:

分析类结构后,需要进行单元测试的函数为 methodD()、methodE()、methodF()。其他函数为初始化或被测函数中调用的函数,都会被自动调用执行。

Activity 中需要完成解析命令执行以上对应 UI 控件函数,根据输入框输入的字符来区分。

由此,Activity 便制作完成。

Espresso 闪亮登场

一切就绪,只欠 Espresso。

Espresso 需要做的事情,就是在已经做好的 Activity 提交不同的已定义命令,来执行 UI 控件不同的函数,并检查结果,达到单元测试目的。

1、以 hideWeekDay(boolean hide) 为例,函数功能为显示/隐藏星期的数字。

用例设计为控件显示星期与隐藏星期,即 hideWeekDay(true) 与 hideWeekDay(false),如隐藏星期的显示,则步骤为:

(1)命令输入框输入 hideWeek(已在 Activity 中做好解析);

(2)点击提交按钮;

(3)检查年正常显示;

(4)检查月正常显示;

(5)检查日正常显示;

(6)检查星期未显示,已隐藏。

测试代码如下:

若隐藏星期显示时,却隐藏了年显示,则会报错。

由此,hideWeekDay(boolean hide) 单元测试完成。

2、再以 getViewDate() 为例,函数功能为获取当前控件显示的时间。

Activity 中解析到输入为 getViewDate 命令时,执行 show.setText(mTimePicker.getViewDate()),将获取的 UI 控件当前时间显示在了 id 为 show 的 TextView 上,以便 Espresso 检查。

用例设计为获取当前控件显示的时间与系统的真实时间对比,并且逐个对比年、月、日、星期是否正确。测试代码如下:

整个 TimePicker 的测试就依此方式测试完成,测试类的结构:

测试报告

Activity 与测试类写好后,PC 连接一台真机,使用命令行进入工程根目录下,运行 gradlewconnectedAndroidTest 命令即可测试与输出测试报告。

html 报告会自动生成,位于工程下 build/reports/androidTests/connected/index.html。

总结

综上,不同的角色处理不同的事务。

Activity 中显示 UI 控件、解析命令与调用 UI 控件函数。

Espresso 自动化输入不同的命令与检查测试结果。

将此测试架构接入 CI 后,可以实现组件构建触发测试,生成测试报告,保证组件开发质量。

扩展

当然,Espresso 不仅局限于此,可以一定程度上取代 Robolectric 与 Uiautomator。

并且,Espresso 与 Uiautomator 依赖可以同时添加在工程中混合使用,也是棒棒哒。

关注微信公众号腾讯移动品质中心 TMQ,获取更多测试干货!

共收到 0 条回复 时间 点赞
wolfgao 移动客户端 /UI 开源测试框架梳理和大比拼 中提及了此贴 02月28日 11:44
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册