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 , 执行的顺序如下

image

套件目录的初始化、清除


点击这里,边看视频讲解,边学习以下内容

刚才我们做到了让一个用例文件里面,所有的用例都共享初始化、清除操作。

如果 多个用例文件里面,的用例都需要相同的初始化清除操作怎么办? 比如目录结构

这时,我们可以使用 整个用例文件的初始化、清除

除了登录测试,其他所有的web界面操作都需要 打开浏览器登录,否则也会导致多次打开浏览器。

可以把打开浏览器的操作设置为 web界面操作目录 共同的初始化

把其他放到 登录后操作 目录中, 添加登录后操作的 初始化

那么怎么设置一个目录共同的初始化呢?

就是 在这个目录下面创建名为 __st__.py 的文件。

和套件文件一样,套件目录的 的初始化、清除 也是在 文件中 添加全局函数 suite_setup、suite_teardown。

请大家根据我们的视频 修改用例目录结构,加上 合适的 初始化、清除 代码。

可以点击这里,下载视频中的示例代码

如果 套件目录有 suite_setup、suite_teardown, 用例文件也有 suite_setup、suite_teardown ,用例里面也有 setup、teardown , 执行的顺序如下所示

image


缺省初始化、清除

用例文件、和套件目录 除了 可以使用 suite_setup、suite_teardown 对整个目录进行初始化清除,还支持另外一种初始化清除: 缺省初识化、清除

就是定义 名称为 test_setuptest_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 订单管理              # 执行 名为 订单管理 的套件

比如,我们想只测试 药品管理 这个套件

run --suite  药品管理  

比如,我们想只测试 界面 - UI-0101 这个用例

run --test  "界面 - UI-0101"  

因为用例名中有空格,所以必须用双引号包起来。

通常,我们的用例名后面会包含用例的 ID, 这样就可以很方便的根据用例ID,来选择用例了

比如 这样

run --test  *0101  

就可以挑选我们 练习中的 用例名为 界面 - UI-0101 的用例执行


假如,你的测试领导,要求做冒烟测试, 挑选出来的用例编号为以下这些:

UI-0301
UI-0302
UI-0303
UI-1401
UI-1402

我们就可以这样执行

run --test *0301  --test *0302 --test *0303 --test *1401 --test *1402

大家自然会想到,如果要执行的用例太多,比如 1000 个,命令行参数岂非太长了?

这时我们可以使用参数文件,可以把所有的参数都放在参数文件中,比如,创建一个名字为 args 的参数文件,内容如下

--test *0301
--test *0302
--test *0303
--test *1401
--test *1402

一行一个参数

然后, 我们的命令就只需要 run -A args 就可以了

用标签挑选用例执行

黑羽robot 还有一种选择测试用例的方法:根据用例的 标签 来挑选用例

给用例添加标签


点击这里,边看视频讲解,边学习以下内容

我们可以给测试用例打上标签(Tag),这样在运行的时候,可以通过标签指定要运行哪些用例。

标签 就是用例的属性特征描述

测试用例可以有多个标签描述它的属性特征, 比如一个登录测试的用例, 可以有3个标签: 登录功能、冒烟测试、UI测试

黑羽robot可以根据任何一个标签选择执行该用例。 这个后面会讲

给用例添加标签有如下几种方式

  • 套件文件全局变量 force_tags

如果我们在测试用例文件 定义了一个名为 force_tags 的全局变量,格式如下

force_tags = ['登录功能','冒烟测试','UI测试']

那么该文件里面所有测试用例都具有了这些标签。

标签一定要放在列表中,即使只有一个标签


如果我们在测试套件目录初始化文件__st__.py定义了一个这样的 force_tags 全局变量, 那么该目录里面所有测试用例都具有了该tag

  • 测试用例类的 tags 静态属性

如果我们在测试用例类 定义了一个名为 tags 静态属性,格式如下

class c00001:
    name = '添加订单 - 00001'
    # 用例标签,可选   
    tags = ['登录功能','冒烟测试','UI测试']

那么本测试用例就具有了这些标签。


根据标签挑选


点击这里,边看视频讲解,边学习以下内容

在执行自动化的时候,我们可以通过命令行参数,指定标签,从而挑选要执行的测试用例

比如:

# 执行包含 标签 '冒烟测试' 的用例. 
--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 后面加 标签名称 来指定哪些用例 是 关键用例 或者 非关键用例。

比如:

run --critical first

指定 只有具有 first 标签的用例才是关键用例 其它都不是


run --noncritical first

指定 具有 first 标签的用例是非关键用例,其他用例都是关键用例。

run --critical basic*  --critical important*

指定 具有 以 basic 开头 或者 important开头 的标签 的用例都是关键用例,其他用例都不是关键用例。



如果我们执行时,指定这个用例为非关键用例,如下所示

run --nocritical order1

然后再看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 参数,使得日志信息更加详细

run -L debug

如果有错误,会打印详细的错误信息,方便定位。

pycharm断点调试

黑羽robot 运行时,做两件事情

  1. 扫描 Python 格式的测试用例 产生对应的 Robotframework 格式的测试用例

  2. 调用 Robotframework 执行测试用例


要断点调试,必须先 执行命令 run.bat --torf,把Python 格式的测试用例转化为 Robotframework格式的用例,然后再调试


黑羽robot 调用 Robotframework 执行测试用例,其实就是 执行类似如下的命令

python -m robot.run cases

上面意思就是执行robot包里面的run.py文件

既然本质上就是一个python程序,当然我们可以在pycharm中执行,以前设置断点的方法依然可以使用

但是我们需要从pycharm里面运行,就需要配置运行参数,点击配置

image


然后,如下图所示,进行配置。注意下图方框里面要点击箭头,从 Script path 改为 Module name

image

这样设置,执行的时候,就等于执行了下面的命令

cd E:\tmp\autotest_bysms
python.exe  -m robot.run  cases

然后再点击debug的图标,就可以进行断点调试了。

您需要高效学习,找工作? 点击咨询 报名实战班

点击查看学员就业情况


课后练习

题目1

使用 hyrobot,完成用例文档中 用例 UI-0103,UI-0105,UI-0106 的自动化。

注意:

  • 做好 合适 的 初始化、清除

  • 用例公共代码 要 放入 库中

题目2

使用 hyrobot,完成用例文档中 剩余用例 的自动化。

根据用例分类, 给用例加上 合适的标签, 然后练习

  • 通过用例名 和 用例标签挑选用例执行

  • 出现问题,根据教程中讲解的方法进行 调试,解决问题。