hyrobot 初始化和清除
创建自己的库
再自动化一个用例
我们先来看一下上次的作业。
要求实现测试用例 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, '获取左侧菜单信息')
# 下面是其余代码
如果自学速度慢、难点搞不定,欢迎来报 实战班 学习。
白月黑羽 1对1连线 讲解答疑,大量练习实战,学习效果是自学没法比的。还有商业项目实战,可以写入简历。
点击这里查看实战班介绍 咨询微信:18502556834
初始化、清除、共享数据
仔细分析,上面两个用例的自动化仍然有问题。
两个用例都要 打开浏览器登陆
如果有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 清除。
课后练习
题目1
使用 hyrobot,完成用例文档中 用例 UI-0103,UI-0105,UI-0106 的自动化。
注意:
-
做好 合适 的
初始化、清除
-
用例公共代码 要 放入 库中
参考答案
VIP 学员联系 老师获取 参考答案 和视频讲解(编码:hyrobot20191208a)