• 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文件:

    1. # Config.py
    2. import os
    3. Base_Dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    4. # 测试数据文件
    5. Test_Data_Path = os.path.join(Base_Dir, 'TestData')

    Util文件夹的find_ele.py文件:

    1. # find_ele.py
    2. from selenium.webdriver.support.wait import WebDriverWait
    3. def find_element(driver, location_type, location_express):
    4. '''查找控件元素'''
    5. try:
    6. driver = WebDriverWait(driver, 20).until(lambda driver:driver.find_element(location_type, location_express))
    7. return driver
    8. except Exception as e:
    9. raise e
    10. def find_elements(driver, location_type, location_express):
    11. '''查找元素组'''
    12. try:
    13. driver = WebDriverWait(driver, 20).until(lambda driver:driver.find_elements(location_type, location_express))
    14. return driver
    15. except Exception as e:
    16. raise e

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

    1. # excel_parse.py
    2. from Setting.Config import Test_Data_Path
    3. from openpyxl import load_workbook
    4. class ExcelParse:
    5. def __init__(self):
    6. self.workbook = None
    7. # self.sheet = None
    8. def load_workbook(self, filename):
    9. '''加载文件'''
    10. try:
    11. self.workbook = load_workbook(filename)
    12. except Exception as e:
    13. raise e
    14. def get_sheet(self, sheetname):
    15. '''获取sheet页'''
    16. try:
    17. # self.sheet = self.workbook[sheetname]
    18. return self.workbook[sheetname]
    19. except Exception as e:
    20. raise e
    21. def get_row_num(self, sheet):
    22. '''返回行数'''
    23. # return self.sheet.max_row
    24. return sheet.max_row
    25. def get_col_num(self, sheet):
    26. '''返回列数'''
    27. # return self.sheet.max_column
    28. return sheet.max_column
    29. def get_cell_value(self, sheet, row, col):
    30. '''返回某一单元格的值'''
    31. # return self.sheet.cell(row=row, column=col).value
    32. return sheet.cell(row=row, column=col).value
    33. def get_row_value(self, sheet, row):
    34. '''返回某一行的值'''
    35. try:
    36. col = self.get_col_num(sheet)
    37. data = []
    38. for i in range(1, col+1):
    39. data.append(self.get_cell_value(sheet, row, i))
    40. return data
    41. except Exception as e:
    42. raise e
    43. def write_cell(self, sheet, row, col, filename, content):
    44. '''单元格赋值'''
    45. try:
    46. # self.sheet.cell(row=row, column=col, value=content)
    47. sheet.cell(row=row, column=col, value=content)
    48. self.workbook.save(filename)
    49. except Exception as e:
    50. raise e
    51. if __name__ == '__main__':
    52. execl = ExcelParse()
    53. execl.load_workbook(Test_Data_Path + '/test_data.xlsx')
    54. sheet = execl.get_sheet('case')
    55. # execl.get_sheet('login')
    56. res = execl.get_row_value(sheet, 2)
    57. print(res)

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

    1. # elementAction.py
    2. import time
    3. from selenium import webdriver
    4. from Util.find_ele import find_element, find_elements
    5. driver = None
    6. def open_browse(browser_name, *args):
    7. '''打开浏览器'''
    8. global driver
    9. try:
    10. if browser_name.lower() == 'chrome':
    11. driver = webdriver.Chrome()
    12. elif browser_name.lower() == 'firefox':
    13. driver = webdriver.Firefox()
    14. else:
    15. driver = webdriver.Ie()
    16. except Exception as e:
    17. raise e
    18. def get_url(url, *args):
    19. '''打开网址'''
    20. try:
    21. driver.get(url)
    22. except Exception as e:
    23. raise e
    24. def max_window(*args):
    25. '''窗口最大化'''
    26. try:
    27. driver.maximize_window()
    28. except Exception as e:
    29. raise e
    30. def switch_frame(location_type, location_express, *args):
    31. '''切换iframe'''
    32. try:
    33. frame = find_element(driver, location_type, location_express)
    34. driver.switch_to.frame(frame)
    35. except Exception as e:
    36. raise e
    37. def input_content(location_type, location_express, content, *args):
    38. '''定位输入框,输入内容'''
    39. try:
    40. find_element(driver, location_type, location_express).send_keys(content)
    41. except Exception as e:
    42. raise e
    43. def input_subject(location_type, location_express, input_conetnt, *args):
    44. '''定位输入框,输入内容'''
    45. try:
    46. # location_express的值为:
    47. location_express, index = location_express.split(',')
    48. find_elements(driver, location_type, location_express)[int(index)].send_keys(input_conetnt)
    49. except Exception as e:
    50. raise e
    51. def switch_default(*args):
    52. '''返回默认iframe'''
    53. try:
    54. driver.switch_to.default_content()
    55. except Exception as e:
    56. raise e
    57. def click(location_type, location_express, *args):
    58. '''点击操作'''
    59. try:
    60. find_element(driver, location_type, location_express).click()
    61. except Exception as e:
    62. raise e
    63. def assert_title(title, *args):
    64. '''断言title是否正确'''
    65. try:
    66. assert title in driver.title
    67. except Exception as e:
    68. raise e
    69. def close_browse():
    70. '''关闭浏览器'''
    71. driver.quit()
    72. def sleep(sec):
    73. '''等待'''
    74. time.sleep(sec)
    75. if __name__ == '__main__':
    76. open_browse('chrome')
    77. get_url('http://mail.163.com')
    78. max_window()
    79. switch_frame('tag name', 'iframe')
    80. input_content('name', 'email', 'YM_yimin')
    81. input_content('name', 'password', 'yimin19960930')
    82. click('id', 'dologin')
    83. assert_title('网易')

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

    1. # common.py
    2. def generate_method_express(location_type, location_express, key_word, operate_data):
    3. # location_type, location_express为空,operate_data不为空
    4. if key_word and operate_data and location_type is None and location_express is None:
    5. # 判断操作值的类型
    6. if isinstance(operate_data, int):
    7. method_express = key_word + '(' + str(operate_data) + ')'
    8. else:
    9. method_express = key_word + "('" + operate_data + "')"
    10. # print(method_express)
    11. # 只有关键字有值,其他的都为空,比如:max_window, close_browse
    12. elif key_word and operate_data is None and location_type is None and location_express is None:
    13. method_express = key_word + '()'
    14. # print(method_express)
    15. # location_type,location_express不为空,operate_data为空
    16. elif key_word and location_type and location_express and operate_data is None:
    17. method_express = key_word + "('" + location_type + "','" + location_express + "')"
    18. # print(method_express)
    19. # 都不为空
    20. else:
    21. if isinstance(operate_data, int):
    22. method_express = key_word + "('" + location_type + "','" + location_express + "'," + str(operate_data) + ")"
    23. else:
    24. method_express = key_word + "('" + location_type + "','" + location_express + "','" + operate_data + "')"
    25. print(method_express)
    26. return method_express

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

    1. # 添加联系人
    2. import time
    3. from Util.common import generate_method_express
    4. from Util.excel_parse import ExcelParse
    5. from Setting.Config import Test_Data_Path
    6. from Util.elementAction import *
    7. from Util import elementAction
    8. from Util.find_ele import find_element
    9. def add_contractors(excel, stepSheet, dataSheet):
    10. '''添加联系人'''
    11. # 数据源行数
    12. data_row_nums = excel.get_row_num(dataSheet)
    13. # 步骤行数
    14. step_row_nums = excel.get_row_num(stepSheet)
    15. # 成功的步骤数
    16. success_record = 0
    17. # 数据驱动sheet页中需要执行的行数
    18. need_run_record = 0
    19. # 遍历数据驱动sheet页中的数据
    20. for i in range(2, data_row_nums):
    21. # 判断数据驱动sheet页的数据是否需要执行
    22. if excel.get_cell_value(dataSheet, i, 6).lower() == 'y':
    23. need_run_record += 1
    24. # 将这一行的数据全部拿出来
    25. name = excel.get_cell_value(dataSheet, i, 1) # 姓名
    26. email = excel.get_cell_value(dataSheet, i, 2) # 邮箱
    27. is_star = excel.get_cell_value(dataSheet, i, 3) # 是否星标
    28. phone = excel.get_cell_value(dataSheet, i, 4) # 电话号码
    29. remarks = excel.get_cell_value(dataSheet, i, 2) # 备注
    30. success_step = 0 # 记录每行数据成功的步骤数
    31. # 编辑关键字驱动sheet页中的步骤
    32. for j in range(2, step_row_nums):
    33. # 获取关键字驱动sheet页中的每行数据
    34. step_desc = excel.get_cell_value(stepSheet, j, 2) # 步骤描述
    35. location_type = excel.get_cell_value(stepSheet, j, 3) # 定位方式
    36. location_express = excel.get_cell_value(stepSheet, j, 4) # 定位方式表达式
    37. keyword = excel.get_cell_value(stepSheet, j, 5) # 关键字
    38. operate_value = excel.get_cell_value(stepSheet, j, 6) # 操作值
    39. # 当操作值是变量的时候,要引用数据源(数据驱动sheet页)中的数据
    40. # operate_value的值是字符串,并且以${开头,}结尾, 例如operate_value='${name}'
    41. if isinstance(operate_value, str) and operate_value.startswith('${') and operate_value.endswith('}'):
    42. # 把operate_value中的变量名截取出来
    43. operate_value = eval(operate_value[2:operate_value.index('}')])
    44. # 组装函数,拼接每个步骤的执行动作函数
    45. func_express = generate_method_express(location_type, location_express, keyword, operate_value)
    46. # 当step_desc为星标是否选择时,当operate_value等于Y(即执行点击操作),选中星标,当operate_value等于Y,不选中星标(即不执行点击操作)
    47. # func_express = click(location_type, location_express, 'Y/N')
    48. if operate_value != 'no_star':
    49. # 执行选中星标,点击操作
    50. try:
    51. eval(func_express)
    52. except Exception as e:
    53. raise e
    54. else:
    55. # 执行选中星标操作,没有异常,成功步骤+1
    56. success_step += 1
    57. else:
    58. # 不执行选中星标操作,要记录成功步骤数
    59. success_step += 1
    60. # 判断成功步骤数,与关键字驱动sheet页的步骤数是否相等
    61. if success_step+1 == step_row_nums:
    62. # 成功步骤数+1 等于 关键字驱动sheet页的行数, 成功的数据+1
    63. success_record += 1
    64. # 将成功的结果写入数据驱动sheet页对应的单元格
    65. excel.write_cell(dataSheet, i, 7, Test_Data_Path+'/test_data.xlsx', 'pass')
    66. else:
    67. excel.write_cell(dataSheet, i, 7, Test_Data_Path + '/test_data.xlsx', 'fail')
    68. # 数据驱动sheet页中的所有数据全部轮训执行完之后
    69. # 判断成功记录数success_record 和 需要执行的数据need_run_record 相等,则说明该测试用例执行成功
    70. if success_record == need_run_record:
    71. return 'Pass'
    72. else:
    73. return 'Fail'
    74. if __name__ == '__main__':
    75. from selenium import webdriver
    76. driver = webdriver.Chrome()
    77. driver.get('http://mail.163.com')
    78. frame = find_element(driver, 'tag name', 'iframe')
    79. driver.switch_to.frame(frame)
    80. find_element(driver, 'name', 'email').send_keys('test123')
    81. find_element(driver, 'name', 'password').send_keys('a123456')
    82. find_element(driver, 'id', 'dologin').click()
    83. time.sleep(5)
    84. elementAction.driver = driver
    85. execl = ExcelParse()
    86. execl.load_workbook(Test_Data_Path + '/test_data.xlsx')
    87. step_sheet = execl.get_sheet('add_person_step')
    88. data_sheet = execl.get_sheet('add_person_data')
    89. add_contractors(execl,step_sheet, data_sheet)

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

    1. # test_login_add_send.py
    2. from Util.excel_parse import ExcelParse
    3. from Setting.Config import Test_Data_Path
    4. from TestScript.add_contractor import add_contractors
    5. from Util.common import generate_method_express
    6. def test_loginAndAddAndSend():
    7. try:
    8. # 获取数据文件case中的内容
    9. excel = ExcelParse()
    10. excel.load_workbook(Test_Data_Path + '/test_data.xlsx')
    11. case_sheet = excel.get_sheet('case') # 获取测试用例sheet页
    12. case_nums = excel.get_row_num(case_sheet) # case的总行数
    13. # 遍历case中的数据
    14. for i in range(2, case_nums+1):
    15. # 判断该用例是否要执行
    16. if excel.get_cell_value(case_sheet, i, 7) == 'y':
    17. # 获取用例名称
    18. case_name = excel.get_cell_value(case_sheet, i, 2)
    19. # 框架类型
    20. frame_mode = excel.get_cell_value(case_sheet, i, 4)
    21. # 步骤sheet名
    22. step_sheet_name = excel.get_cell_value(case_sheet, i, 5)
    23. stepsheet = excel.get_sheet(step_sheet_name) # 获取步骤sheet页
    24. if frame_mode == 'data':
    25. # 如果框架类型为data,获取数据sheet名
    26. data_sheet_name = excel.get_cell_value(case_sheet, i, 6)
    27. # 分别获取两个sheet,作为参数传入
    28. datasheet = excel.get_sheet(data_sheet_name)
    29. result = None
    30. # 调用对应的方法,即添加联系人的方法
    31. if case_name == 'add_person':
    32. result = add_contractors(excel, stepsheet, datasheet)
    33. if result == 'Pass':
    34. excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Pass')
    35. else:
    36. excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Fail')
    37. elif frame_mode == 'key':
    38. # 获取步骤数
    39. step_nums = excel.get_row_num(stepsheet)
    40. # 记录成功的步骤数
    41. success_step_num = 0
    42. for j in range(2, step_nums+1):
    43. # 步骤描述
    44. step_desc = excel.get_cell_value(stepsheet, j, 2)
    45. location_type = step_desc = excel.get_cell_value(stepsheet, j, 3)
    46. location_express = step_desc = excel.get_cell_value(stepsheet, j, 4)
    47. key_word = excel.get_cell_value(stepsheet, j, 5)
    48. operate_value = step_desc = excel.get_cell_value(stepsheet, j, 6)
    49. # 构建函数表达式
    50. func_express = generate_method_express(location_type, location_express, key_word, operate_value)
    51. # 执行函数, 不抛出异常就认为执行成功
    52. try:
    53. print(f'开始执行 {step_desc}')
    54. eval(func_express)
    55. except Exception as e:
    56. print(f'执行{step_desc}发生异常{e}')
    57. # 某一步发生异常,则该用例执行失败,将失败结果写入测试用例(case)sheet页
    58. excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Fail')
    59. else:
    60. success_step_num += 1
    61. # 执行成功步骤数+1 = 步骤总数,用例执行成功
    62. if success_step_num+1 == step_nums:
    63. # 写入成功
    64. excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Pass')
    65. else:
    66. excel.write_cell(case_sheet, i, 8, Test_Data_Path + '/test_data.xlsx', 'Skip')
    67. except Exception as e:
    68. raise e

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

  • 相关阅读:
    【嵌入式linux开发】智能家居入门6:最新ONENET,物联网开放平台(QT、微信小程序、MQTT协议、ONENET云平台、旭日x3派)
    【芯片前端】四年经验|芯片前端|IP设计岗|面试问题|总结分享
    【Unity2022】Unity实现在两个物体之间连出一条线
    为什么不应该在 Flutter 中使用全局变量
    Linux系统编程_进程:C程序空间分配、fork、wait、exec、system、popen
    .NET Core使用SkiaSharp快速生成二维码( 真正跨平台方案)
    Node.js学习篇(三)安装express编写get和post请求及安装nodemon
    2594. 修车的最少时间
    4本建模必读的书籍,每天学一点,获益匪浅
    CentOS:7 源码安装zeek
  • 原文地址:https://blog.csdn.net/weixin_48323589/article/details/132643742