UI自动化之混合框架

什么是混合框架,混合框架就是将数据驱动与关键字驱动结合在一起,主要用来回归业务主流程,将核心流程串联起来。

上一篇我们写到了关键字驱动框架,关键字驱动框架是针对一个业务场景的单条测试用例的。

我们以163邮箱的登录到创建联系人这个流程为例,来看看混合框架是怎样的。

首先准备一个存放测试用例和数据的excel文件,文件内容如下:

测试用例的sheet页:case

mock表示这条测试用例我们需要用到的框架模型,key表示关键字,data表示数据

step_sheet表示这条用例我们需要用到的关键字驱动的sheet页名称

data_sheet表示这条用例我们需要用到的数据驱动的sheet页名称

login_step页:

add_person_step页:添加联系人的步骤

add_person_data页:添加联系人所需要用到的数据

excel的准备工作就完成了,接下来看代码:

首先是项目目录:只写了简单的几个目录,其他的目录在pageobject三层架构中写过,可以参考,都是一样的。

Setting文件夹的Config.py文件:

python 复制代码
# Config.py
import os

Base_Dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# 测试数据文件
Test_Data_Path = os.path.join(Base_Dir, 'TestData')

Util文件夹的find_ele.py文件:

python 复制代码
# find_ele.py
from selenium.webdriver.support.wait import WebDriverWait


def find_element(driver, location_type, location_express):
    '''查找控件元素'''
    try:
        driver = WebDriverWait(driver, 20).until(lambda driver:driver.find_element(location_type, location_express))
        return driver
    except Exception as e:
        raise e


def find_elements(driver, location_type, location_express):
    '''查找元素组'''
    try:
        driver = WebDriverWait(driver, 20).until(lambda driver:driver.find_elements(location_type, location_express))
        return driver
    except Exception as e:
        raise e

Util文件夹的excel_parse.py文件:读取excel的内容

python 复制代码
# excel_parse.py
from Setting.Config import Test_Data_Path
from openpyxl import load_workbook

class ExcelParse:

    def __init__(self):
        self.workbook = None
        # self.sheet = None

    def load_workbook(self, filename):
        '''加载文件'''
        try:
            self.workbook = load_workbook(filename)
        except Exception as e:
            raise e

    def get_sheet(self, sheetname):
        '''获取sheet页'''
        try:
            # self.sheet = self.workbook[sheetname]
            return self.workbook[sheetname]
        except Exception as e:
            raise e

    def get_row_num(self, sheet):
        '''返回行数'''
        # return self.sheet.max_row
        return sheet.max_row

    def get_col_num(self, sheet):
        '''返回列数'''
        # return self.sheet.max_column
        return sheet.max_column

    def get_cell_value(self, sheet, row, col):
        '''返回某一单元格的值'''
        # return self.sheet.cell(row=row, column=col).value
        return sheet.cell(row=row, column=col).value

    def get_row_value(self, sheet, row):
        '''返回某一行的值'''
        try:
            col = self.get_col_num(sheet)
            data = []
            for i in range(1, col+1):
                data.append(self.get_cell_value(sheet, row, i))
            return data
        except Exception as e:
            raise e

    def write_cell(self, sheet, row, col, filename, content):
        '''单元格赋值'''
        try:
            # self.sheet.cell(row=row, column=col, value=content)
            sheet.cell(row=row, column=col, value=content)
            self.workbook.save(filename)

        except Exception as e:
            raise e


if __name__ == '__main__':
    execl = ExcelParse()
    execl.load_workbook(Test_Data_Path + '/test_data.xlsx')
    sheet = execl.get_sheet('case')
    # execl.get_sheet('login')
    res = execl.get_row_value(sheet, 2)
    print(res)

Util文件夹的elementAction.py文件:执行动作的封装

python 复制代码
# elementAction.py
import time

from selenium import webdriver
from Util.find_ele import find_element, find_elements

driver = None

def open_browse(browser_name, *args):
    '''打开浏览器'''
    global driver
    try:
        if browser_name.lower() == 'chrome':
            driver = webdriver.Chrome()
        elif browser_name.lower() == 'firefox':
            driver = webdriver.Firefox()
        else:
            driver = webdriver.Ie()
    except Exception as e:
        raise e

def get_url(url, *args):
    '''打开网址'''
    try:
        driver.get(url)
    except Exception as e:
        raise e


def max_window(*args):
    '''窗口最大化'''
    try:
        driver.maximize_window()
    except Exception as e:
        raise e

def switch_frame(location_type, location_express, *args):
    '''切换iframe'''
    try:
        frame = find_element(driver, location_type, location_express)
        driver.switch_to.frame(frame)
    except Exception as e:
        raise e

def input_content(location_type, location_express, content, *args):
    '''定位输入框,输入内容'''
    try:
        find_element(driver, location_type, location_express).send_keys(content)
    except Exception as e:
        raise e

def input_subject(location_type, location_express, input_conetnt, *args):
    '''定位输入框,输入内容'''
    try:
        # location_express的值为:
        location_express, index = location_express.split(',')
        find_elements(driver, location_type, location_express)[int(index)].send_keys(input_conetnt)
    except Exception as e:
        raise e


def switch_default(*args):
    '''返回默认iframe'''
    try:
        driver.switch_to.default_content()
    except Exception as e:
        raise e


def click(location_type, location_express, *args):
    '''点击操作'''
    try:
        find_element(driver, location_type, location_express).click()
    except Exception as e:
        raise e

def assert_title(title, *args):
    '''断言title是否正确'''
    try:
        assert title in driver.title
    except Exception as e:
        raise e


def close_browse():
    '''关闭浏览器'''
    driver.quit()


def sleep(sec):
    '''等待'''
    time.sleep(sec)

if __name__ == '__main__':
    open_browse('chrome')
    get_url('http://mail.163.com')
    max_window()
    switch_frame('tag name', 'iframe')
    input_content('name', 'email', 'YM_yimin')
    input_content('name', 'password', 'yimin19960930')
    click('id', 'dologin')
    assert_title('网易')

Util文件夹的common.py文件:封装拼接的执行动作函数

python 复制代码
# common.py
def generate_method_express(location_type, location_express, key_word, operate_data):
    # location_type, location_express为空,operate_data不为空
    if key_word and operate_data and location_type is None and location_express is None:
        # 判断操作值的类型
        if isinstance(operate_data, int):
            method_express = key_word + '(' + str(operate_data) + ')'
        else:
            method_express = key_word + "('" + operate_data + "')"
        # print(method_express)
    # 只有关键字有值,其他的都为空,比如:max_window, close_browse
    elif key_word and operate_data is None and location_type is None and location_express is None:
        method_express = key_word + '()'
        # print(method_express)
    # location_type,location_express不为空,operate_data为空
    elif key_word and location_type and location_express and operate_data is None:
        method_express = key_word + "('" + location_type + "','" + location_express + "')"
        # print(method_express)
    # 都不为空
    else:
        if isinstance(operate_data, int):
            method_express = key_word + "('" + location_type + "','" + location_express + "'," + str(operate_data) + ")"
        else:
            method_express = key_word + "('" + location_type + "','" + location_express + "','" + operate_data + "')"
        print(method_express)
    return method_express

TestScript文件夹下的add_contractor.py文件:添加联系人的测试用例执行

python 复制代码
# 添加联系人
import time

from Util.common import generate_method_express
from Util.excel_parse import ExcelParse
from Setting.Config import Test_Data_Path
from Util.elementAction import *
from Util import elementAction
from Util.find_ele import find_element


def add_contractors(excel, stepSheet, dataSheet):
    '''添加联系人'''
    # 数据源行数
    data_row_nums = excel.get_row_num(dataSheet)
    # 步骤行数
    step_row_nums = excel.get_row_num(stepSheet)
    # 成功的步骤数
    success_record = 0
    # 数据驱动sheet页中需要执行的行数
    need_run_record = 0
    # 遍历数据驱动sheet页中的数据
    for i in range(2, data_row_nums):
        # 判断数据驱动sheet页的数据是否需要执行
        if excel.get_cell_value(dataSheet, i, 6).lower() == 'y':
            need_run_record += 1
            # 将这一行的数据全部拿出来
            name = excel.get_cell_value(dataSheet, i, 1)   # 姓名
            email = excel.get_cell_value(dataSheet, i, 2)   # 邮箱
            is_star = excel.get_cell_value(dataSheet, i, 3)   # 是否星标
            phone = excel.get_cell_value(dataSheet, i, 4)    # 电话号码
            remarks = excel.get_cell_value(dataSheet, i, 2)   # 备注

            success_step = 0     # 记录每行数据成功的步骤数
            # 编辑关键字驱动sheet页中的步骤
            for j in range(2, step_row_nums):
                # 获取关键字驱动sheet页中的每行数据
                step_desc = excel.get_cell_value(stepSheet, j, 2)         # 步骤描述
                location_type = excel.get_cell_value(stepSheet, j, 3)     # 定位方式
                location_express = excel.get_cell_value(stepSheet, j, 4)   # 定位方式表达式
                keyword = excel.get_cell_value(stepSheet, j, 5)           # 关键字
                operate_value = excel.get_cell_value(stepSheet, j, 6)      # 操作值

                # 当操作值是变量的时候,要引用数据源(数据驱动sheet页)中的数据
                # operate_value的值是字符串,并且以${开头,}结尾, 例如operate_value='${name}'
                if isinstance(operate_value, str) and operate_value.startswith('${') and operate_value.endswith('}'):
                    # 把operate_value中的变量名截取出来
                    operate_value = eval(operate_value[2:operate_value.index('}')])
                # 组装函数,拼接每个步骤的执行动作函数
                func_express = generate_method_express(location_type, location_express, keyword, operate_value)

                # 当step_desc为星标是否选择时,当operate_value等于Y(即执行点击操作),选中星标,当operate_value等于Y,不选中星标(即不执行点击操作)
                # func_express = click(location_type, location_express, 'Y/N')
                if operate_value != 'no_star':
                    # 执行选中星标,点击操作
                    try:
                        eval(func_express)
                    except Exception as e:
                        raise e
                    else:
                        # 执行选中星标操作,没有异常,成功步骤+1
                        success_step += 1
                else:
                    # 不执行选中星标操作,要记录成功步骤数
                    success_step += 1
            # 判断成功步骤数,与关键字驱动sheet页的步骤数是否相等
            if success_step+1 == step_row_nums:
                # 成功步骤数+1 等于 关键字驱动sheet页的行数, 成功的数据+1
                success_record += 1
                # 将成功的结果写入数据驱动sheet页对应的单元格
                excel.write_cell(dataSheet, i, 7, Test_Data_Path+'/test_data.xlsx', 'pass')
            else:
                excel.write_cell(dataSheet, i, 7, Test_Data_Path + '/test_data.xlsx', 'fail')
    # 数据驱动sheet页中的所有数据全部轮训执行完之后
    # 判断成功记录数success_record 和 需要执行的数据need_run_record  相等,则说明该测试用例执行成功
    if success_record == need_run_record:
        return 'Pass'
    else:
        return 'Fail'


if __name__ == '__main__':
    from selenium import webdriver
    driver = webdriver.Chrome()
    driver.get('http://mail.163.com')
    frame = find_element(driver, 'tag name', 'iframe')
    driver.switch_to.frame(frame)
    find_element(driver, 'name', 'email').send_keys('test123')
    find_element(driver, 'name', 'password').send_keys('a123456')
    find_element(driver, 'id', 'dologin').click()
    time.sleep(5)

    elementAction.driver = driver

    execl = ExcelParse()
    execl.load_workbook(Test_Data_Path + '/test_data.xlsx')
    step_sheet = execl.get_sheet('add_person_step')
    data_sheet = execl.get_sheet('add_person_data')
    add_contractors(execl,step_sheet, data_sheet)

TestScript文件夹的test_login_add_send.py文件:读取case页的测试用例,进行执行

python 复制代码
# test_login_add_send.py
from Util.excel_parse import ExcelParse
from Setting.Config import Test_Data_Path
from TestScript.add_contractor import add_contractors
from Util.common import generate_method_express

def test_loginAndAddAndSend():
    try:
        # 获取数据文件case中的内容
        excel = ExcelParse()
        excel.load_workbook(Test_Data_Path + '/test_data.xlsx')
        case_sheet = excel.get_sheet('case')    # 获取测试用例sheet页
        case_nums = excel.get_row_num(case_sheet)     # case的总行数
        # 遍历case中的数据
        for i in range(2, case_nums+1):
            # 判断该用例是否要执行
            if excel.get_cell_value(case_sheet, i, 7) == 'y':
                # 获取用例名称
                case_name = excel.get_cell_value(case_sheet, i, 2)
                # 框架类型
                frame_mode = excel.get_cell_value(case_sheet, i, 4)
                # 步骤sheet名
                step_sheet_name = excel.get_cell_value(case_sheet, i, 5)
                stepsheet = excel.get_sheet(step_sheet_name)   # 获取步骤sheet页
                if frame_mode == 'data':
                    # 如果框架类型为data,获取数据sheet名
                    data_sheet_name = excel.get_cell_value(case_sheet, i, 6)
                    # 分别获取两个sheet,作为参数传入
                    datasheet = excel.get_sheet(data_sheet_name)
                    result = None
                    # 调用对应的方法,即添加联系人的方法
                    if case_name == 'add_person':
                        result = add_contractors(excel, stepsheet, datasheet)
                        if result == 'Pass':
                            excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Pass')
                        else:
                            excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Fail')
                elif frame_mode == 'key':
                    # 获取步骤数
                    step_nums = excel.get_row_num(stepsheet)
                    # 记录成功的步骤数
                    success_step_num = 0
                    for j in range(2, step_nums+1):
                        # 步骤描述
                        step_desc = excel.get_cell_value(stepsheet, j, 2)
                        location_type = step_desc = excel.get_cell_value(stepsheet, j, 3)
                        location_express = step_desc = excel.get_cell_value(stepsheet, j, 4)
                        key_word = excel.get_cell_value(stepsheet, j, 5)
                        operate_value = step_desc = excel.get_cell_value(stepsheet, j, 6)
                        # 构建函数表达式
                        func_express = generate_method_express(location_type, location_express, key_word, operate_value)

                        # 执行函数, 不抛出异常就认为执行成功
                        try:
                            print(f'开始执行 {step_desc}')
                            eval(func_express)
                        except Exception as e:
                            print(f'执行{step_desc}发生异常{e}')
                            # 某一步发生异常,则该用例执行失败,将失败结果写入测试用例(case)sheet页
                            excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Fail')
                        else:
                            success_step_num += 1
                    # 执行成功步骤数+1 = 步骤总数,用例执行成功
                    if success_step_num+1 == step_nums:
                        # 写入成功
                        excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Pass')
            else:
                excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Skip')

    except Exception as e:
        raise e

最后执行test_login_add_send.py文件,即实现了混合框架。

相关推荐
drebander24 分钟前
使用 Java Stream 优雅实现List 转化为Map<key,Map<key,value>>
java·python·list
威威猫的栗子1 小时前
Python Turtle召唤童年:喜羊羊与灰太狼之懒羊羊绘画
开发语言·python
墨染风华不染尘1 小时前
python之开发笔记
开发语言·笔记·python
Dxy12393102162 小时前
python bmp图片转jpg
python
麦麦大数据2 小时前
Python棉花病虫害图谱系统CNN识别+AI问答知识neo4j vue+flask深度学习神经网络可视化
人工智能·python·深度学习
LKID体2 小时前
Python操作neo4j库py2neo使用之创建和查询(二)
数据库·python·neo4j
LKID体2 小时前
Python操作neo4j库py2neo使用之py2neo 删除及事务相关操作(三)
开发语言·python·neo4j
小屁孩大帅-杨一凡2 小时前
Python-flet实现个人视频播放器
开发语言·python·音视频
算家云2 小时前
快速识别模型:simple_ocr,部署教程
开发语言·人工智能·python·ocr·数字识别·检测模型·英文符号识别
Thomas_Cai2 小时前
Python后端flask框架接收zip压缩包方法
开发语言·python·flask