过程记录方式
当前,AppiumBooster已实现的记录形式有如下三种:
logger模块:可指定日志级别对测试过程进行记录
截图功能:测试用例运行过程中,在每个步骤执行完成后进行截图
DOM source:测试用例运行过程中,在每个步骤执行完成后保存当前页面的DOM内容
测试结果存储
由于Appium分为Server端和Client端,因此AppiumBooster在记录日志的时候也将日志分为了三份:
appium_server.log: Appium Server端的日志,这部分日志是由Appium框架打印的
appium_booster.log: 包括测试环境初始化和测试用例执行记录,这部分日志是由AppiumBooster中采用logger模块打印的
client_server.log: 同时记录AppiumBooster和Appium框架的日志,相当于appium_server.log和appium_booster.log的并集,优点在于可以清晰地看到测试用例执行过程中Client端和Server端的通讯交互过程
另外,当测试用例执行失败时,AppiumBooster会将执行失败的步骤截图和日志提取出来,单独保存到errors文件夹中,方便问题追溯。
具体地,每次执行测试前,AppiumBooster会在指定的results目录下创建一个以当前时间(%Y-%m-%d_%H:%M:%S)命名的文件夹,存储结构如下所示。
2016-08-28_16:28:48 ├── appium_server.log ├── appium_booster.log ├── client_server.log ├── errors │ ├── 16_31_29_btnLogin.click.dom │ ├── 16_31_29_btnLogin.click.png │ ├── 16_32_03_btnMenuMyAccount.click.dom │ └── 16_32_03_btnMenuMyAccount.click.png ├── screenshots │ ├── 16_30_34_tablecellMyAccountLogin.click.png │ ├── 16_30_41_txtfieldEmailAddress.type_leo.lee@debugtalk.com.png │ ├── 16_30_48_sectxtfieldPassword.type_123456.png │ ├── 16_31_29_btnLogin.click.png │ └── 16_32_03_btnMenuMyAccount.click.png └── xmls ├── 16_30_34_tablecellMyAccountLogin.click.dom ├── 16_30_41_txtfieldEmailAddress.type_leo.lee@debugtalk.com.dom ├── 16_30_48_sectxtfieldPassword.type_123456.dom ├── 16_31_29_btnLogin.click.dom └── 16_32_03_btnMenuMyAccount.click.dom |
对于每一个测试步骤的截图和DOM,存储文件命名格式为%H_%M_%S_ControlID.ControlAction。采用这种命名方式有两个好处:
文件通过时间排序,对应着测试用例执行的步骤顺序
可以在截图或DOM中直观地看到每一步操作指令对应的执行结果
环境初始化
Appium Server
在执行自动化测试时,某些情况下可能会造成Appium Server出现异常情况(e.g. 500 error),并影响到下一次测试的执行。
为了避免这类情况,AppiumBooster在每次执行测试前,会强制性地对Appium Server进行重启。方式也比较简单暴力,运行测试之前先检查系统是否有bin/appium的进程在运行,如果有,则先kill掉该进程,然后再启动Appium Server。
需要说明的是,由于Appium Server的启动需要一定时间,为了防止运行Appium Client时Appium Server还未初始化完毕,因此启动Appium Server后最好能等待一段时间(e.g. sleep 10s)。
iOS/Android模拟器
在模拟器中运行一段时间后,也会存在缓存数据和文件,可能会对下一次测试造成影响。
为了避免这类情况,AppiumBooster在每次执行测试前,会先删除已存在的模拟器,然后再用指定的模拟器配置创建新的模拟器。
对于iOS模拟器,AppiumBooster通过调用xcrun simctl命令的方式来对模拟器进行操作,基本原理如下所示。
# delete iOS simulator: xcrun simctl delete device_id $ xcrun simctl delete F2F53866-50A5-4E0F-B164-5AC1702AD1BD # create iOS simulator: xcrun simctl create device_type device_type_id runtime_id $ xcrun simctl create 'iPhone 5' 'com.apple.CoreSimulator.SimDeviceType.iPhone-5' 'com.apple.CoreSimulator.SimRuntime.iOS-9-3' |
其中,device_id/device_type_id/runtime_id这些属性值可以通过执行xcrun simctl list命令获取得到。
$ xcrun simctl list == Device Types == iPhone 5s (com.apple.CoreSimulator.SimDeviceType.iPhone-5s) iPhone 6 (com.apple.CoreSimulator.SimDeviceType.iPhone-6) == Runtimes == iOS 8.4 (8.4 - 12H141) (com.apple.CoreSimulator.SimRuntime.iOS-8-4) iOS 9.3 (9.3 - 13E230) (com.apple.CoreSimulator.SimRuntime.iOS-9-3) == Devices == -- iOS 8.4 -- iPhone 5s (E1BD9CC5-8E95-408F-849C-B0C6A44D669A) (Shutdown) -- iOS 9.3 -- iPhone 5s (BAFEFBE1-3ADB-45C4-9C4E-E3791D260524) (Shutdown) iPhone 6 (F23B3F85-7B65-4999-9F1C-80111783F5A5) (Shutdown) == Device Pairs == |
增强特性
除了以上基础特性,AppiumBooster还支持一些辅助特性,可以增强测试框架的使用体验。
Data参数化
在某些场景下,测试用例执行时需要动态获取数值。例如,注册账号的测试用例中,每次执行测试用例时需要保证用户名为未注册的,常见的做法就是在注册用户名中包含时间戳。
AppiumBooster的做法是,可以在测试步骤的data字段中,传入Ruby表达式,格式为${ruby_expression}。在执行测试用例时,会先对ruby_expression进行eval计算,然后用计算得到的值作为实际参数。
回到刚才的注册账号测试用例,填写用户名的步骤就可以按照如下形式指定参数。
input test EmailAddress: control_id: txtfieldEmailAddress control_action: type data: ${Time.now.to_i}@debugtalk.com expectation: sectxtfieldPassword |
实际执行测试用例时,data就会参数化为`1471318368@debugtalk.com`的形式。
全局参数配置
对于某些配置参数,例如系统的登录账号密码等,虽然可以直接填写到测试用例的steps中,但是终究不够灵活。特别是当存在多个测试用例引用同一个参数时,涉及到参数改动时就需要同时修改多个地方。
更好的做法是,将此类参数提取出来,在统一的地方进行配置。在AppiumBooster中,可以在config.yml文件中配置全局参数。
--- TestEnvAccount: UserName: test@debugtalk.com Password: 123456 ProductionEnvAccount: UserName: production@debugtalk.com Password: 12345678 |
然后,在测试用例的steps就可以采用如下形式对全局参数进行引用。
--- AccountSteps: input test EmailAddress: control_id: txtfieldEmailAddress control_action: type data: ${config.TestEnvAccount.UserName} expectation: sectxtfieldPassword input test Password: control_id: sectxtfieldPassword control_action: type data: ${config.TestEnvAccount.Password} expectation: btnLogin |
optional选项
在执行测试用例时,有时候可能会存在这样的场景:某个步骤作为非必要步骤,当其执行失败时,我们并不想将测试用例判定为不通过。
基于该场景,在测试用例设计表格中增加了optional参数。该参数值默认不用填写。但如果在某个步骤对应的optional栏填写了true值后,那么该步骤就会作为非必要步骤,其执行结果不会影响整个用例的执行结果。
例如,在电商类APP中,某些账号有优惠券,登录系统后,会弹出优惠券的提示框;而有的账号没有优惠券,登录后就不会有这样的弹框。那么关闭优惠券弹框的步骤就可以将其optional参数设置为true。
--- AccountSteps: close coupon popup window(optional): control_id: btnClose control_action: click expectation: !btnViewMyCoupons optional: true |
命令行工具
AppiumBooster通过在命令行中进行调用。
$ ruby start.rb -h Usage: start.rb [options] -p, --app_path <value> Specify app path -t, --app_type <value> Specify app type, ios or android -f, --testcase_file <value> Specify testcase file(s) -d, --output_folder <value> Specify output folder -c, --convert_type <value> Specify testcase converter, yaml2csv or csv2yaml --disable_output_color Disable output color |
执行测试用例
指定执行测试用例时支持多种方式,常见的几种使用方式示例如下:
$ cd ${AppiumBooster} # 执行指定的测试用例文件(绝对路径) $ ruby run.rb -p "ios/app/test.zip" -f "/Users/Leo/MyProjects/AppiumBooster/ios/testcases/login.yml" # 执行指定的测试用例文件(相对路径) $ ruby run.rb -p "ios/app/test.zip" -f "ios/testcases/login.yml" # 执行所有yaml格式的测试用例文件 $ ruby run.rb -p "ios/app/test.zip" -f "ios/testcases/*.yml" # 执行ios目录下所有csv格式的测试用例文件 $ ruby run.rb -p "ios/app/test.zip" -t "ios" -f "*.csv" |
测试用例转换
将YAML格式的测试用例转换为CSV格式的测试用例:
$ ruby start.rb -c "yaml2csv" -f ios/testcases/login_and_logout.yml |
总结
什么才算是心目中理想的自动化测试框架?我也没有确切的答案。
为什么要登山?
因为山在那里。
上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。