hyrobot 使用说明2
创建自己的库
再自动化一个用例
我们先来看一下上次的作业。
要求实现测试用例 UI-0102.
和前面的操作一样,我们写一个新的类 c0102 对应 这个用例。
然后拷贝以前 Selenium 课程中已经实现的代码 放入到 teststeps 方法中。
参考代码如下
# 类名保证唯一,推荐包含用例编号
class c0102:
name = '管理员首页 - UI-0102'
# 测试用例步骤
def teststeps(self):
STEP(1, '登陆网站')
from selenium import webdriver
from time import sleep
wd = webdriver.Chrome()
wd.implicitly_wait(5)
wd.get('http://127.0.0.1/mgr/sign.html')
# 根据 ID 选择元素,并且输入字符串
wd.find_element_by_id('username').send_keys('byhy')
wd.find_element_by_id('password').send_keys('88888888')
# 根据标签名查找元素
wd.find_element_by_tag_name('button').click()
STEP(2, '点击左侧客户菜单')
# 先找到上层节点,缩小查找范围
sidebarMenu = wd.find_element_by_class_name('sidebar-menu')
# 再找到内部元素
elements = sidebarMenu.find_elements_by_tag_name('span')
# 第一个span对应的菜单是 客户,点击它
elements[0].click()
STEP(3, '添加客户')
# 点击添加客户按钮
wd.find_element_by_class_name('glyphicon-plus').click()
# form-contorl 对应3个输入框
inputs = wd.find_element_by_class_name('add-one-area') \
.find_elements_by_class_name('form-control')
# 输入客户姓名
inputs[0].send_keys('南京中医院')
# 输入联系电话
inputs[1].send_keys('2551867858')
# 输入客户描述
inputs[2].send_keys('江苏省-南京市-秦淮区-汉中路-16栋504')
# 第1个 btn-xs 就是创建按钮, 点击创建按钮
wd.find_element_by_class_name('add-one-area') \
.find_element_by_class_name('btn-xs') \
.click()
# 等待1秒
sleep(1)
STEP(4, '检查添加信息')
# 找到 列表最上面的一栏
item = wd.find_elements_by_class_name('search-result-item')[0]
fields = item.find_elements_by_tag_name('span')[:6]
texts = [field.text for field in fields]
print(texts)
# 预期内容为
expected = [
'客户名:',
'南京中医院',
'联系电话:',
'2551867858',
'地址:',
'江苏省-南京市-秦淮区-汉中路-16栋504'
]
CHECK_POINT('客户信息和添加内容一致 ',
texts == expected)
wd.quit()
公共代码放入库中
仔细检查代码我们可以发现用例1 和 用例2 的登录代码是 完全相同的。
为了 去除 冗余代码,我们应该 把登录的代码放到一个单独的库文件中,
比如,在 lib 目录下新建一个 库文件 webui.py 。 其代码如下:
from selenium import webdriver
def open_browser():
print('打开浏览器')
wd = webdriver.Chrome()
wd.implicitly_wait(5)
return wd
def mgr_login(wd):
wd.get('http://127.0.0.1/mgr/sign.html')
# 根据 ID 选择元素,并且输入字符串
wd.find_element_by_id('username').send_keys('byhy')
wd.find_element_by_id('password').send_keys('88888888')
# 根据标签名查找元素
wd.find_element_by_tag_name('button').click()
然后修改测试用例,里面使用 库文件 webui.py
如下所示
from lib.webui import *
class c0101:
name = '管理员首页 - UI-0101' # 测试用例名字
# 测试用例步骤
def teststeps(self):
STEP(1, '登陆网站')
wd = open_browser()
mgr_login(wd)
STEP(2, '获取左侧菜单信息')
# 下面是其余代码
您需要高效学习,找工作? 点击咨询 报名实战班
点击查看学员就业情况
初始化、清除、共享数据
仔细分析,上面两个用例的自动化仍然有问题。
两个用例都要 打开浏览器登陆
如果有100个这样的用例,就执行100次登录的操作。
这两个用例 重点其实不在登录,而是后面的操作。
两个用例后面的操作 需要的初始环境是一样的 : 打开浏览器并且登录 的环境
能不能共享执行环境?
共享什么执行环境?用例执行的时候,就处于 打开浏览器并且登录 的环境
就是我们用例执行时,就获取一个 WebDriver对象, 对应 已经登陆好管理员账号 的浏览器,后面的代码直接就可以使用这个 WebDriver对象 执行操作。
怎么 让自动化 用例执行的时候,就有一个 打开浏览器并且登录 的 初始环境
呢?
这就需要 初始化
(英文叫 setup
)操作
初始化 就是: 为 一个或者多个测试用例执行时,构建所需要的数据环境。
与初始化正好相反的操作就是 清除
(英文叫 teardown
)。
初始化 是 创建环境,清除 是 还原(或者说销毁)
环境
为什么需要 清除 来 还原环境?
因为 执行完测试用例后 可能会对数据环境产生改变,这种改变后的数据环境,可能会影响 其它用例的执行(不需要这种数据环境的用例)
比如:
用例A 测试系统中存在用户账号,使用该账号进行登录,期望结果是登录成功
用例B 测试系统中没有任何账号,使用不存在的账号进行登录,期望结果是登录失败。
为了执行用例A,我们初始化操作里面创建了一个账号user1
执行完后,需要执行用例B,那么这个创建的user1账号,就破坏了用例B所需要的数据环境(系统中没有账号)
这就需要在执行完用例A 后,执行一个 清除(还原)操作, 把添加的用户账号user1 删除掉。
可能有的朋友说,那也可以在用例B的初始化操作里面删除所有账号啊。
那样做,会使得 每个用例的初始化 工作变得非常难。 因为 不知道自动化测试的时候,会执行哪些用例,这些用例执行后 可能会产生什么多余的数据。
所以一个原则是:
谁
做的 初始化
操作对环境产生了 什么改变
, 谁
就应该在 清除
操作里面做什么样的 还原
。
自己拉的屎,自己擦屁股,不要让别人帮你擦,而且还要擦干净。
黑羽robot的初始化/清除(和robotframework一样)支持 3种方式
- 单个用例的初始化、清除
- 整个用例文件的初始化、清除
- 整个用例目录的初始化、清除
单个用例的初始化、清除
首先看第一种:
单个用例的初始化、清除 是在 用例对应的类里面添加setup、teardown 方法
class c0101:
name = '管理员首页 - UI-0101'
# 初始化方法
def setup(self):
wd = open_browser()
mgr_login(wd)
#清除方法
def teardown(self):
wd = get_global_webdriver()
wd.quit()
# 测试用例步骤
def teststeps(self):
# 获取webdriver对象 对应 已经登录好的浏览器
wd = get_global_webdriver()
STEP(1, '获取左侧菜单信息')
然后修改 库文件 webui.py ,如下
def open_browser():
print('打开浏览器')
wd = webdriver.Chrome()
wd.implicitly_wait(5)
# 使用黑羽robot 全局存储对象 GSTORE
GSTORE['global_webdriver'] = wd
return wd
# 获取 全局使用的 webdriver 对象
def get_global_webdriver():
return GSTORE['global_webdriver']
注意: 我们在创建 WebDriver 对象后,把它存到了 黑羽robot 全局存储对象 GSTORE 中。 方便其他的代码 获取。
黑羽robot执行用例时
-
先执行 setup 里面的代码
-
再执行 teststeps 里面的代码
-
最后再执行 teardown 里面的代码。
而且
如果 setup 执行失败(有 异常), 就不会再执行 teststeps 和 teardown 里面的代码了。
如果 teststeps 执行失败, 仍然会执行 teardown , 确保环境被 清除
用例文件的初始化、清除
精明的读者肯定已经发现,上面这种单个用例的初始化、清除,并没有解决我们前面说的 多个用例共享 数据环境的问题。
这时,我们可以使用 整个用例文件的初始化、清除
整个 用例文件 的初始化、清除 是在 文件中 添加全局函数 suite_setup、suite_teardown
如下所示
from hyrobot.common import *
from lib.webui import *
from time import sleep
def suite_setup():
INFO('suite_setup')
wd = open_browser()
mgr_login(wd)
def suite_teardown():
INFO('suite_teardown')
wd = get_global_webdriver()
wd.quit()
class c0101:
# 测试用例名字
name = '管理员首页 - UI-0101'
# 测试用例步骤
def teststeps(self):
wd = get_global_webdriver()
STEP(1, '获取左侧菜单信息')
# 先找到上层节点,缩小查找范围
sidebarMenu = wd.find_element_by_class_name('sidebar-menu')
# 再找到内部元素
elements = sidebarMenu.find_elements_by_tag_name('span')
menuTitles = []
for ele in elements:
INFO(ele.text)
menuTitles.append(ele.text)
STEP(2, '检查是否正确')
CHECK_POINT("侧边栏菜单是否正确",
menuTitles[:3] == ['客户', '药品', '订单'])
class c0102:
name = '管理员首页 - UI-0102'
# 测试用例步骤
def teststeps(self):
wd = get_global_webdriver()
STEP(1, '点击左侧客户菜单')
# 先找到上层节点,缩小查找范围
sidebarMenu = wd.find_element_by_class_name('sidebar-menu')
# 再找到内部元素
elements = sidebarMenu.find_elements_by_tag_name('span')
# 第一个span对应的菜单是 客户,点击它
elements[0].click()
STEP(2, '添加客户')
# 点击添加客户按钮
wd.find_element_by_class_name('glyphicon-plus').click()
# form-contorl 对应3个输入框
inputs = wd.find_element_by_class_name('add-one-area') \
.find_elements_by_class_name('form-control')
# 输入客户姓名
inputs[0].send_keys('南京中医院')
# 输入联系电话
inputs[1].send_keys('2551867858')
# 输入客户描述
inputs[2].send_keys('江苏省-南京市-秦淮区-汉中路-16栋504')
# 第1个 btn-xs 就是创建按钮, 点击创建按钮
wd.find_element_by_class_name('add-one-area') \
.find_element_by_class_name('btn-xs') \
.click()
# 等待1秒
sleep(1)
STEP(3, '检查添加信息')
# 找到 列表最上面的一栏
item = wd.find_elements_by_class_name('search-result-item')[0]
fields = item.find_elements_by_tag_name('span')[:6]
texts = [field.text for field in fields]
print(texts)
# 预期内容为
expected = [
'客户名:',
'南京中医院',
'联系电话:',
'2551867858',
'地址:',
'江苏省-南京市-秦淮区-汉中路-16栋504'
]
CHECK_POINT('客户信息和添加内容一致 ',
texts == expected)
如果一个 用例文件 既有 suite_setup、suite_teardown ,用例里面也有 setup、teardown , 执行的顺序如下
套件目录的初始化、清除
刚才我们做到了让一个用例文件里面,所有的用例都共享初始化、清除操作。
如果 多个用例文件里面,的用例都需要相同的初始化清除操作怎么办? 比如目录结构
这时,我们可以使用 整个用例文件的初始化、清除
除了登录测试,其他所有的web界面操作都需要 打开浏览器登录,否则也会导致多次打开浏览器。
可以把打开浏览器的操作设置为 web界面操作目录 共同的初始化
把其他放到 登录后操作 目录中, 添加登录后操作的 初始化
那么怎么设置一个目录共同的初始化呢?
就是 在这个目录下面创建名为 __st__.py
的文件。
和套件文件一样,套件目录的 的初始化、清除 也是在 文件中 添加全局函数 suite_setup、suite_teardown。
请大家根据我们的视频 修改用例目录结构,加上 合适的 初始化、清除 代码。
如果 套件目录有 suite_setup、suite_teardown, 用例文件也有 suite_setup、suite_teardown ,用例里面也有 setup、teardown , 执行的顺序如下所示
缺省初始化、清除
用例文件、和套件目录 除了 可以使用 suite_setup、suite_teardown 对整个目录进行初始化清除,还支持另外一种初始化清除: 缺省初识化、清除
就是定义 名称为 test_setup
和 test_teardown
的全局函数。
如果在 用例文件 中定义了 全局函数 test_setup
,如果 该文件中 有用例本身没有初始化
方法, 执行自动化的时候就会对该用例,使用这个 test_setup 初始化
如果在 用例文件 中定义了 全局函数 test_teardown
,如果 该文件中 有用例本身没有清除
方法, 执行自动化的时候就会对该用例,使用这个 test_teardown 清除。
执行自动化测试的时候,往往我们并不需要执行 全部的
测试用例。
比如:冒烟测试,只需要测试冒烟测试的那些用例。 或者调试自己写的某个用例的自动化,就只需要执行那一个用例。
黑羽robot 可以灵活的挑选要执行的测试用例。
黑羽robot是基于 robotframework 的, 挑选用例执行的机制和 robotframework 完全一致
用名字挑选用例执行
我们可以通过 --test
或者 --suite
命令行参数 来指定执行哪些用例或者套件,而且还支持用通配符的方式。
--test testA # 执行名为 testA 的用例
--test testA --test testB # 执行名为 testA 和 testB 的用例
--test test* # 执行名字以 test 开头的用例
--suite 订单管理 # 执行 名为 订单管理 的套件
比如,我们想只测试 药品管理
这个套件
比如,我们想只测试 界面 - UI-0101
这个用例
因为用例名中有空格,所以必须用双引号包起来。
通常,我们的用例名后面会包含用例的 ID, 这样就可以很方便的根据用例ID,来选择用例了
比如 这样
就可以挑选我们 练习中的 用例名为 界面 - UI-0101
的用例执行
假如,你的测试领导,要求做冒烟测试, 挑选出来的用例编号为以下这些:
我们就可以这样执行
大家自然会想到,如果要执行的用例太多,比如 1000 个,命令行参数岂非太长了?
这时我们可以使用参数文件,可以把所有的参数都放在参数文件中,比如,创建一个名字为 args 的参数文件,内容如下
一行一个参数
然后, 我们的命令就只需要 run -A args
就可以了
用标签挑选用例执行
黑羽robot 还有一种选择测试用例的方法:根据用例的 标签
来挑选用例
给用例添加标签
我们可以给测试用例打上标签(Tag),这样在运行的时候,可以通过标签指定要运行哪些用例。
标签 就是用例的属性特征描述
测试用例可以有多个标签描述它的属性特征, 比如一个登录测试的用例, 可以有3个标签: 登录功能、冒烟测试、UI测试
黑羽robot可以根据任何一个标签选择执行该用例。 这个后面会讲
给用例添加标签有如下几种方式
- 套件文件全局变量 force_tags
如果我们在测试用例文件 定义了一个名为 force_tags 的全局变量,格式如下
那么该文件里面所有测试用例都具有了这些标签。
标签一定要放在列表中,即使只有一个标签
如果我们在测试套件目录初始化文件__st__.py定义了一个这样的 force_tags 全局变量, 那么该目录里面所有测试用例都具有了该tag
- 测试用例类的 tags 静态属性
如果我们在测试用例类 定义了一个名为 tags 静态属性,格式如下
那么本测试用例就具有了这些标签。
根据标签挑选
在执行自动化的时候,我们可以通过命令行参数,指定标签,从而挑选要执行的测试用例
比如:
# 执行包含 标签 '冒烟测试' 的用例.
--include 冒烟测试
# 执行不包含标签 '冒烟测试' 的用例.
--exclude 冒烟测试
# 执行 有冒烟测试、UITest 两个标签的用例
--include 冒烟测试ANDUITest
# 执行 有 冒烟测试 或者 UITest 标签 的用例
--include 冒烟测试 --include UITest
# 执行标签格式为 A*B 的用例,比如 A5B, AB, A444B
--include A*B
指定关键测试用例
黑羽robot 执行时,可以指定用例是否是 关键(critical)
测试用例。
如果本次测试中有关键测试用例没有通过,整个测试就被视为测试不通过。 即使100个用例中只有1个关键用例没有通过,
反之,所有关键用例都通过,整个测试就视为通过。 即使100个中有99个非关键用例没有通过,只有1个关键通过。
黑羽robot 执行测试时,如果没有命令行参数特别指定,每个测试用例都被视为关键测试用例。
我们可以修改下面的的用例,故意产生错误
class c1401:
name = '订单管理 - UI-1401'
tags = 'order1'
def teststeps(self):
STEP(1,'添加订单')
STEP(2,'检查结果')
# 故意产生错误
raise Exception()
当我们运行 黑羽robot 发现 有用例不通过, 然后再看Report, 发现测试报告底色是红色的。 表示整个测试是失败的。
因为缺省都是critical, 所以用红色表示测试不通过
我们可以通过命令参数 --critical
或 --noncritical
后面加 标签名称 来指定哪些用例 是 关键用例 或者 非关键用例。
比如:
指定 只有具有 first 标签的用例才是关键用例 其它都不是
指定 具有 first 标签的用例是非关键用例,其他用例都是关键用例。
指定 具有 以 basic 开头 或者 important开头 的标签 的用例都是关键用例,其他用例都不是关键用例。
如果我们执行时,指定这个用例为非关键用例,如下所示
然后再看Report, 发现测试报告底色是绿色的。因为这个用例都变成非关键用例了,即使失败,也认为测试结果是通过的。
一些特殊参数
- 清除所有robot用例文件
使用参数 run.bat --delrf
删除已经存在的 robotframework格式的用例,不执行测试
- 只转化Python用例为robotframework格式用例
使用参数 run.bat --torf
只执行转化Python用例为RF用例,不执行转化好的RF测试用例
- 只运行测试
使用参数 run.bat --runrf
直接执行已经存在的robotframework用例,不执行转化Python用例为RF用例操作
- 只汉化测试报告
使用参数 run.bat --hanrf
只执行把测试报告汉化的工作,不执行转化和测试
调试
黑羽robot运行后,如果发现 程序出现了问题,怎么去 debug 呢?
debug 日志级别
在命令行加上 -L debug
参数,使得日志信息更加详细
如果有错误,会打印详细的错误信息,方便定位。
pycharm断点调试
黑羽robot 运行时,做两件事情
-
扫描 Python 格式的测试用例 产生对应的 Robotframework 格式的测试用例
-
调用 Robotframework 执行测试用例
要断点调试,必须先 执行命令 run.bat --torf
,把Python 格式的测试用例转化为 Robotframework格式的用例,然后再调试
黑羽robot 调用 Robotframework 执行测试用例,其实就是 执行类似如下的命令
上面意思就是执行robot包里面的run.py文件
既然本质上就是一个python程序,当然我们可以在pycharm中执行,以前设置断点的方法依然可以使用
但是我们需要从pycharm里面运行,就需要配置运行参数,点击配置
然后,如下图所示,进行配置。注意下图方框里面要点击箭头,从 Script path 改为 Module name
这样设置,执行的时候,就等于执行了下面的命令
然后再点击debug的图标,就可以进行断点调试了。
您需要高效学习,找工作? 点击咨询 报名实战班
点击查看学员就业情况
课后练习
题目1
使用 hyrobot,完成用例文档中 用例 UI-0103,UI-0105,UI-0106 的自动化。
注意:
-
做好 合适 的
初始化、清除
-
用例公共代码 要 放入 库中
题目2
使用 hyrobot,完成用例文档中 剩余用例 的自动化。
根据用例分类, 给用例加上 合适的标签, 然后练习
-
通过用例名 和 用例标签挑选用例执行
-
出现问题,根据教程中讲解的方法进行 调试,解决问题。