初始化和清除

创建自己的库

再自动化一个用例


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

我们先来看一下上次的作业。

要求实现测试用例 UI-0102.

和前面的操作一样,我们写一个新的类 c2 对应 这个用例。

然后拷贝以前 Selenium 课程中已经实现的代码 放入到 teststeps 方法中。

参考代码如下

class c2:
    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 c1:    
    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 c1:
    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 c1:
    # 测试用例名字
    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 c2:
    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 清除。




扫码分享给朋友,一起学更有动力哦




课后练习

题目1

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

注意:

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

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



参考答案

VIP 学员联系 老师获取 参考答案 和视频讲解(编码:hyrobot20191208a)