使用ruby+cucumber编写测试用例
前言
前面介绍了Appium的环境配置和元素定位技巧,一些就绪后,马上开始单元测试用例的编写吧,下面手把手教你编写测试用例
下面例子全部使用Sublime Text编辑器编写
1、新建文件夹
在合适的位置创建测试目录,例子
cd Desktop
mkdir 测试用例
2、创建Gemfile文件,导入ruby依赖库
source 'https://www.rubygems.org'
gem 'appium_lib', '~> 9.7.4'
gem 'rest-client', '~> 2.0.2'
gem 'rspec', '~> 3.6.0'
gem 'cucumber', '~> 2.4.0'
gem 'rspec-expectations', '~> 3.6.0'
gem 'spec', '~> 5.3.4'
gem 'sauce_whisk', '~> 0.0.13'
gem 'test-unit', '~> 2.5.5' # required for bundle exec ruby xunit_android.rb
Gem 是 Ruby 模块 (叫做 Gems) 的包管理器。其包含包信息,以及用于安装的文件。
Gem通常是依照".gemspec"文件构建的,包含了有关Gem信息的YAML文件。Ruby代码也可以直接建立Gem,这种情况下通常利用Rake来进行。
3、安装ruby依赖库
在命令行输入下面命令
bundle install
4、初始化cucumber
cucumber --init
执行上面命令,会生成如下目录结构
features # 存放feature的目录
├── step_definitions # 存放steps的目录
└── support # 环境配置
└── env.rb
5、新建apps目录
mkdir apps
将目标.app文件拖到apps目录下,注意:这里如果使用模拟器测试,需要app文件是以模拟器架构(eg: iPhone 8)编译的,如果使用真机测试,那么app文件需要使用真机架构编译(eg: Generic iOS Device)
补充:打开工程,command+U,build完成之后,可在工程的Products目录下看到app文件
6、设置Appium服务器初始化参数
新建文件appium.txt
使用xcrun simctl list devices查看可用的设备
image.png设置Desired Capabilities,例如
[caps]
# 模拟器
platformName = "ios"
deviceName = "iPhone 8"
platformVersion = "11.1"
app = "/Users/yangfangming/Desktop/TuanFund-Appium/apps/TuanFundApp/build/TuandaiFund.app"
automationName = "XCUITest"
参数描述
键 | 描述 | 值 |
---|---|---|
automationName | 自动化测试的引擎 | 例如 XCUITest、uiautomator2 |
platformName | 使用的手机操作系统 | 例如 iOS, Android, 或者 FirefoxOS
|
platformVersion | 手机操作系统的版本 | 例如 7.1, 4.4 |
deviceName | 使用的手机或模拟器类型 | 例如 iPhone 8,Nexus_5X |
app | 本地绝对路径或远程 http URL 所指向的一个安装包(.ipa,.apk,或 .zip 文件) | /abs/path/to/my.apk 或 http://myapp.com/app.ipa |
7、根据appium.txt配置的参数,初始化全局的driver对象
打开env.rb文件,输入如下代码
require 'rspec/expectations'
require 'appium_lib'
require 'cucumber/ast'
# Create a custom World class so we don't pollute `Object` with Appium methods
class AppiumWorld
end
# Load the desired configuration from appium.txt, create a driver then
# Add the methods to the world
caps = Appium.load_appium_txt file: File.expand_path('../appium.txt', __FILE__), verbose: true
Appium::Driver.new(caps)
Appium.promote_appium_methods AppiumWorld
World do
AppiumWorld.new
end
Before { $driver.start_driver }
After { $driver.driver_quit }
8、新建feature文件,这里以登录为例,新建login.feature文件,输入如下代码
#language: zh-CN
功能: 账户测试
# 作为一个开发者
# 我已经注册了用户名为18576771524,密码为123456a的账号
# 我希望能使用这个账号登录
场景: 验证登录成功
假如 广告或者引导页面存在,跳过广告和引导页面
当 点击 "我的"
并且 点击 "登录/注册"
并且 在用户名输入框输入 18576771524
并且 在密码输入框输入 123456 "a"
并且 点击 "登录"
并且 等待 3 秒
那么 登录页面应该消失
创建login.feature文件后,有个小技巧,执行bundle exec cucumber
运行测试用例(确保Appium服务端端已经启动),由于这里还没有创建steps,会提示如下信息
9、创建steps,根据上面的提示创建loginSteps.rb文件
最终目录结构如下
├── Gemfile # ruby依赖库
├── Gemfile.lock # 依赖库版本管理
├── apps # 目标app
│ └── TuandaiFund.app
└── features # 存放feature、steps的目录
├── login.feature
├── step_definitions # 存放steps的目录
│ └── loginSteps.rb
└── support # 环境配置
├── appium.txt
└── env.rb
编写steps
假如(/^广告或者引导页面存在,跳过广告和引导页面$/) do
pending # Write code here that turns the phrase above into concrete actions
end
当(/^点击 "([^"]*)"$/) do |arg1|
pending # Write code here that turns the phrase above into concrete actions
end
当(/^在用户名输入框输入 (\d+)$/) do |arg1|
pending # Write code here that turns the phrase above into concrete actions
end
当(/^在密码输入框输入 (\d+) "([^"]*)"$/) do |arg1, arg2|
pending # Write code here that turns the phrase above into concrete actions
end
当(/^等待 (\d+) 秒$/) do |arg1|
pending # Write code here that turns the phrase above into concrete actions
end
那么(/^登录页面应该消失$/) do
pending # Write code here that turns the phrase above into concrete actions
end
编写steps可借助Appium的元素检查器appium inspector,如何启动inspector,如何定位元素和操作,前面环境配置和Appium_lib已经说过了,这里不再赘述
值得一提的是Gherkin中的关键字,假如、当、并且、那么等是等价的语法糖
假如(/^点击 "([^"]*)"$/) do
end
当(/^点击 "([^"]*)"$/) do
end
并且(/^点击 "([^"]*)"$/) do
end
上面3个steps是等价的,如果有多个当 点击 xx 按钮
这样的feature,只能保留其中一个,否则运行测试用例的时候会报冲突的错误
编写完成之后的loginSteps.rb文件如下:
# 跳过广告页面
def dismiss_ad_View
adExist = exists { id("广告页面") }
if adExist
sleep(5)
end
end
# 跳过引导页面
def dismiss_guide_page
guideExist = exists { id("引导页面") }
# guideExist ? puts("引导页面存在") : puts("引导页面不存在")
if guideExist
swipe(direction: "left", element: nil)
sleep(1)
swipe(direction: "left", element: nil)
sleep(1)
button("进入首页").click
sleep(1)
end
end
# 跳过手势密码页面
def dismiss_gestrure_password_page
gestureExist = exists { id("手势密码页面") }
# guideExist ? puts("引导页面存在") : puts("引导页面不存在")
if gestureExist
swipe(direction: "right", element: nil)
sleep(1)
swipe(direction: "right", element: nil)
sleep(1)
end
end
假如(/^广告或者引导页面存在,跳过广告和引导页面$/) do
dismiss_ad_View
dismiss_guide_page
dismiss_gestrure_password_page
end
# 按钮点击
当(/^点击 "([^"]*)"$/) do |arg1|
e = exists { button(arg1) }
if e
btn = button(arg1)
else
btn = driver.find_element(:id, arg1)
end
wait { btn.click }
end
当(/^在用户名输入框输入 (\d+)$/) do |arg1|
textfield("请输入手机号").type arg1
end
当(/^在密码输入框输入 (\d+) "([^"]*)"$/) do |arg1, arg2|
textfield("请输入密码").type arg1+arg2
end
# 延时执行
当(/^等待 (\d+) 秒$/) do |arg1|
sleep(arg1.to_i)
end
那么(/^登录页面应该消失$/) do
# 期望:登录页面dismiss
actual = exists { id("登录页面") }
expect(actual).to eq(false)
end
现在进入测试用例
目录运行bundle exec cucumber
查看测试效果吧
如果你想使用python来编写单元测试,可参考这里