前言
基于这一痛点,我开发了AppiumBooster框架。顾名思义,AppiumBooster基于Appium实现,但更简单和易于使用;测试人员不用接触任何代码,就可以直接采用简洁优雅的方式来编写和维护自动化测试用例。
原型开发完毕后,我将其应用在当前所在团队的项目上,并在使用的过程中,按照自己心目中理想的自动化测试框架的模样对其进行迭代优化,最终打磨成了一个自己还算用得顺手的自动化测试框架。
本文便是对AppiumBooster的核心特性及其设计思想进行介绍。在内容组织上,本文的各个部分相对独立,大家可直接选择自己感兴趣的部分进行阅读。
UI交互基础
UI交互是自动化测试的基础,主要分为三部分内容:定位控件、操作控件、检测结果。
控件定位
定位控件时,统一采用元素ID进行定位。这里的ID包括accessibility_id或accessibility_label,需要在iOS工程项目中预先进行设置。
另外,考虑到控件可能出现延迟加载的情况,定位控件时统一执行wait操作;定位成功后会立即返回控件对象,定位失败时会进行等待并不断尝试定位,直到超时(30秒)后抛出异常。
wait { id control_id } |
源码路径:AppiumBooster/lib/pages/control.rb
控件操作
根据实践证明,UI的控件操作基本主要就是点击、输入和滑动,这三个操作基本上可以覆盖绝大多数场景。
scrollToDisplay: 根据指定控件的坐标位置,对屏幕进行上/下/左/右滑动操作,直至将指定控件展示在屏幕中
click: 通过控件ID定位到指定控件,并对指定控件进行click操作;若指定控件不在当前屏幕中,则先执行scrollToDisplay,再执行click操作
type(text): 在指定控件中输入字符串;若指定控件不在当前屏幕中,则先执行scrollToDisplay,再执行输入操作
tapByCoordinate: 先执行scrollToDisplay,确保指定控件在当前屏幕中;获取指定控件的坐标值,然后对坐标进行tap操作
scroll(direction): 对屏幕进行指定方向的滑动
源码路径:AppiumBooster/lib/pages/actions.rb
预期结果检查
每次执行一步操作后,需要对执行结果进行判断,以此来确定测试用例的各个步骤是否执行成功。
当前,AppiumBooster采用控件的ID作为检查对象,并统一封装到check_elements(control_ids)方法中。
在实际使用过程中,需要先确定当前步骤执行完成后的跳转页面的特征控件,即当前步骤执行前不存在该控件,但执行成功后的页面中具有该控件。然后在操作步骤描述的expectation属性中指定特征控件的ID。
具体地,在指定控件ID的时候还可以配合使用操作符(!,||,&&),以此实现多种复杂场景的检测。典型的预期结果描述形式如下:
A: 预期控件A存在;
!A: 预期控件A不存在;
A||B: 预期控件A或控件B至少存在一个;
A&&B: 预期控件A和控件B同时存在;
A&&!B: 预期控件A存在,但控件B不存在;
!A&&!B: 预期控件A和控件B都不存在。
源码路径:AppiumBooster/lib/pages/inner_screen.rb
测试用例引擎(YAML)
对于自动化测试而言,自动化测试用例的组织与管理是最为重要的部分,直接关系到自动化测试用例的可复用性和可维护性。
经过综合考虑,AppiumBooster从三个层面来描述测试用例,从低到高分别是step、feature和testcase;描述方式推荐使用YAML格式。
steps(测试步骤描述)
首先是对于单一操作步骤的描述。
从UI层面来看,每一个操作步骤都可以归纳为三个方面:定位控件、操作控件和检查结果。
AppiumBooster的做法是,将App根据功能模块进行拆分,每一个模块单独创建一个YAML文件,并保存在steps目录下。然后,在每个模块中以控件为单位,分别进行定义。
现以如下示例进行详细说明。
--- AccountSteps: enter Login page: control_id: tablecellMyAccountLogin control_action: click expectation: btnForgetPassword input test EmailAddress: control_id: txtfieldEmailAddress control_action: type data: leo.lee@debugtalk.com expectation: sectxtfieldPassword check if coupon popup window exists(optional): control_id: inner_screen control_action: has_control data: btnViewMyCoupons expectation: btnClose optional: true |
其中,AccountSteps是steps模块名称,用于区分不同的steps模块,方便在features模块中进行引用。
描述单个步骤时,有三项是必不可少的:步骤名称、控件ID(control_id)和控件操作方式(control_action)。当控件操作方式为输入(type)时,则还需指定data属性,即输入内容。
在检查步骤执行结果方面,可通过在expectation属性中指定控件ID进行实现,前面在预期结果检查一节中已经详细介绍了使用方法。该属性可以置空或不进行填写,相当于不对当前步骤进行检测。
另外还有一个optional属性,对步骤指定该属性并设置为true时,当前步骤的执行结果不影响整个测试用例。
features(功能点描述)
各个模块的单一操作步骤定义完毕后,虽然可以直接将多个步骤进行组合形成对测试场景的描述,即测试用例,但是操作起来会过于局限细节;特别是当测试用例较多时,可维护性是一个很大的问题。
AppiumBooster的做法是,将App根据功能模块进行拆分,每一个模块单独创建一个YAML文件,并保存在features目录下。然后,在每个模块中以功能点为单位,通过对steps模块中定义好的操作步骤进行引用并组合,即可实现对功能点的描述。
以系统登录功能为例,功能点的描述可采用如下形式。
--- AccountFeatures: login with valid test account: - AccountSteps | enter My Account page - AccountSteps | enter Login page - AccountSteps | input test EmailAddress - AccountSteps | input test Password - AccountSteps | login - AccountSteps | close coupon popup window(optional) login with valid production account: - AccountSteps | enter My Account page - AccountSteps | enter Login page - AccountSteps | input production EmailAddress - AccountSteps | input production Password - AccountSteps | login - AccountSteps | close coupon popup window(optional) logout: - AccountSteps | enter My Account page - SettingsSteps | enter Settings page - AccountSteps | logout |
其中,AccountFeatures是features模块名称,用于区分不同的features模块,方便在testcase中进行引用。
在引用steps模块的操作步骤时,需要同时指定steps模块名称和操作步骤的名称,并以|进行分隔。
testcases(测试用例描述)
在功能点描述的基础上,AppiumBooster就可以在第三个层面,简单清晰地描述测试用例了。
具体做法很简单,针对每个测试用例创建一个YAML文件,并保存在testcases目录下。然后,通过对features模块中定义好的功能点描述进行引用并组合,即可实现对测试用例的描述。
同样的,在引用features模块的功能点时,也需要同时指定features模块名称和功能点的名称,并以|进行分隔。
如下示例便是实现了在商城中购买商品的整个流程,包括切换国家、登录、选择商品、添加购物车、下单完成支付等功能点。
--- Buy Phantom 4: - SettingsFeatures | initialize first startup - SettingsFeatures | Change Country to China - AccountFeatures | login with valid account - AccountFeatures | Change Shipping Address to China - StoreFeatures | add phantom 4 to cart - StoreFeatures | finish order - AccountFeatures | logout |
另外,在某些测试场景中可能需要重复进行某一个功能点的操作。虽然可以将需要重复的步骤多写几次,但会显得比较累赘,特别是重复次数较多时更是麻烦。
AppiumBooster的做法是,在测试用例的步骤中可指定执行次数,并以|进行分隔,如下例所示。
-- Send random text messages: - SettingsFeatures | initialize first startup - AccountFeatures | login with valid test account - MessageFeatures | enter follower user message page - MessageFeatures | send random text message | 100 |
测试用例引擎(CSV)
基本上,YAML测试用例引擎已经可以很好地满足组织和管理自动化测试用例的需求。
但考虑到部分用户会偏向于使用表格的形式,因为表格看上去更直观一些,AppiumBooster同时还支持CSV格式的测试用例引擎。
testcases(测试用例描述)
采用表格来编写测试用例时,只需要在任意表格工具,包括Microsoft Excel、iWork Numbers、WPS等,按照如下形式对测试用例进行描述。
然后,将表格内容另存为CSV格式的文件,并放置于testcases目录中即可。
可以看出,CSV格式的测试用例和YAML格式的测试用例是等价的,两者包含的信息内容完全相同。
在具体实现上,AppiumBooster在执行测试用例之前,也会将两个测试用例引擎的测试用例描述转换为相同的数据结构,然后再进行统一的操作。
统一转换后的数据结构如下所示:
{ "testcase_name": "Login and Logout", "features_suite": [ { "feature_name": "login with valid account", "feature_steps": [ {"control_id": "btnMenuMyAccount", "control_action": "click", "expectation": "tablecellMyAccountSystemSettings", "step_desc": "enter My Account page"}, {"control_id": "tablecellMyAccountLogin", "control_action": "click", "expectation": "btnForgetPassword", "step_desc": "enter Login page"}, {"control_id": "txtfieldEmailAddress", "control_action": "type", "data": "leo.lee@debugtalk.com", "expectation": "sectxtfieldPassword", "step_desc": "input EmailAddress"}, {"control_id": "sectxtfieldPassword", "control_action": "type", "data": 12345678, "expectation": "btnLogin", "step_desc": "input Password"}, {"control_id": "btnLogin", "control_action": "click", "expectation": "tablecellMyMessage", "step_desc": "login"}, {"control_id": "btnClose", "control_action": "click", "expectation": nil, "optional": true, "step_desc": "close coupon popup window(optional)"} ] }, { "feature_name": "logout", "feature_steps": [ {"control_id": "btnMenuMyAccount", "control_action": "click", "expectation": "tablecellMyAccountSystemSettings", "step_desc": "enter My Account page"}, {"control_id": "tablecellMyAccountSystemSettings", "control_action": "click", "expectation": "txtCountryDistrict", "step_desc": "enter Settings page"}, {"control_id": "btnLogout", "control_action": "click", "expectation": "uiviewMyAccount", "step_desc": "logout"} ] } ] } |
测试用例转换器(yaml2csv)
既然CSV格式的测试用例和YAML格式的测试用例是等价的,那么两者之间的转换也就容易实现了。
当前,AppiumBooster支持将YAML格式的测试用例转换为CSV格式的测试用例,只需要执行一条命令即可。
$ ruby start.rb -c "yaml2csv" -f ios/testcases/login_and_logout.yml |
过程记录及结果存储
在自动化测试执行过程中,应尽量对测试用例执行过程进行记录,方便后续对问题根据定位和追溯。
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。