python seleniumunittest 及 ddt 数据驱动测试
Posted jianeng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python seleniumunittest 及 ddt 数据驱动测试相关的知识,希望对你有一定的参考价值。
PO模型的概念和理解:
PO就是一个设计思想,将代码以页面为单位进行组织,针对这个页面上的所有信息、相关操作都放到一个类中,从而使具体的测试用例变成了简单的调用和验证操作。
优点:进行了拆分和分层
缺点:对于复杂的业务page层变了,case也需要去改动
目录结构:
run_main.py 执行文件
common 公共方法
data 存放配置文件、元素定位文件、测试数据文件
logs 存放日志文件
report 测试报告
pageobj 页面元素
action 页面操作
testcase 测试用例
1、执行文件
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 import os import sys import unittest from common.HTMLTestRunner import HTMLTestRunner from common.logger import Log # 当前脚本所在文件真实路径 CUR_PATH = os.path.dirname(os.path.realpath(__file__)) # 日志 log = Log() def add_case(case_name="testcase", rule="test*.py"): """ 第一步:加载所有的测试用例 :meth case_name: 测试用例文件夹名称 type: str :meth rule: 匹配规则 type: str :return: """ # 用例文件夹路径 case_path = os.path.join(CUR_PATH, case_name) # 如果不存在这个case文件夹,就自动创建一个 if not os.path.exists(case_path): os.mkdir(case_path) log.info("test case path: %s" % case_path) # 定义discover方法的参数 discover = unittest.defaultTestLoader.discover(case_path, pattern=rule, top_level_dir=None) return discover def run_case(all_case, report_name="report"): """ 第二步:执行所有的用例, 并把结果写入 HTML 测试报告 :meth all_case: 所有测试用例 type: str :meth report_name: 测试报告文件夹名称 type: str :return: """ # now = time.strftime("_%Y-%m-%d %H-%M-%S") now = "" # 测试报告文件夹 report_dir = os.path.join(CUR_PATH, report_name) # 如果不存在这个report文件夹,就自动创建 if not os.path.exists(report_dir): os.mkdir(report_dir) report_abspath = os.path.join(report_dir, "TestResult" + now + ".html") log.info("report path: %s" % report_abspath) fp = open(report_abspath, "wb") runner = HTMLTestRunner(stream=fp, title=‘自动化测试报告,测试结果如下:‘, description=‘用例执行情况:‘) # 调用 add_case 函数返回值 log.info("----- 开始执行测试用例 -----") runner.run(all_case) log.info("----- 结束执行测试用例 -----") fp.close() def main(): case_dir = "testcase/gateway/check" # case_dir = "testcase" # # 测试项目 # program = sys.argv[1] # if program == "gateway": # case_dir = "testcase/gateway/pay" # elif program == "check": # case_dir = "testcase/gateway/check" # 1、加载用例 load_case = add_case(case_dir) # 2、执行用例 run_case(load_case) if __name__ == "__main__": main()
2、公共方法目录
页面基本操作
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 import win32gui import win32con import time import platform from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support.select import Select from selenium.webdriver.common.action_chains import ActionChains from common.logger import Log # 日志 log = Log() class Action(object): """ BasePage封装所有页面的公共方法 """ def __init__(self, selenium_driver): """ 初始化 driver :meth selenium_driver: 浏览器驱动 """ self.driver = selenium_driver def _open(self, url, page_title): """ 打开页面,校验页面链接是否加载正确 :meth url: 链接地址 type: str :meth page_title: 页面标题 type: str :return: """ # 使用get打开访问链接地址 self.driver.get(url) try: # 使用assert进行校验,打开的链接地址是否与配置的地址一致, 调用on_page()方法 assert self.on_page(page_title), "打开页面失败 {}".format(url) except Exception as err: log.error("打开页面失败 %s" % err) raise Exception("打开页面失败") def open(self, base_url, page_title): """ 定义 open 方法,调用 _open() 打开链接 :return: """ self._open(base_url, page_title) def on_page(self, page_title): """ 使用 current_url 获取当前窗口 url 地址,进行与配置地址作比较,返回比较结果(True or False) :meth page_title: 页面标题 type: str :return: type: bool """ return page_title in self.driver.title def find_element(self, time_out=10, *loc): """ 重写元素定位方法(单个元素) :meth time_out: 超时时间 type: int :meth loc: 元素定位 type: str :return: """ try: # 等待元素出现 # WebDriverWait(self.driver, 10).until(self.driver.find_element(*loc).is_displayed()) WebDriverWait(self.driver, time_out).until(lambda driver: driver.find_element(*loc).is_displayed()) return self.driver.find_element(*loc) except Exception as err: log.error("%s 页面中未能找到 %s 元素 页面链接:%s %s" % (self.driver.title, loc, self.driver.current_url, err)) def find_elements(self, time_out=10, *loc): """ 重写元素定位方法(多个元素) :meth time_out: 超时时间 type: int :meth loc: 元素定位 type: str :return: """ try: # 等待元素出现 WebDriverWait(self.driver, time_out).until(lambda driver: driver.find_element(*loc).is_displayed()) return self.driver.find_elements(*loc) except Exception as err: log.error("%s 页面中未能找到 %s 元素 页面链接:%s %s" % (self.driver.title, loc, self.driver.current_url, err)) def upload_file(self, loc, file_path): """ 上传文件 :param loc: 元素定位 type: tuple :param file_path: 文件路径 type: str :return: """ try: # 点击上传按钮 self.click_button(loc) # 判断是哪个操作系统 if platform.system() == "Windows": file_path = file_path.replace("/", "\\") # 主窗口(上传文件对话框), chrome 浏览器弹窗标题是"打开", firefox 浏览器弹窗标题是"文件上传" dialog = win32gui.FindWindow(‘#32770‘, ‘打开‘) # 重试次数 num = 5 for i in range(num): # 判断是否获取到窗口句柄 if dialog == 0: time.sleep(1) dialog = win32gui.FindWindow(‘#32770‘, ‘打开‘) else: # 上面三句依次寻找对象,直到找到输入框 edit 对象的句柄 combobox_ex32 = win32gui.FindWindowEx(dialog, 0, ‘ComboBoxEx32‘, None) combobox = win32gui.FindWindowEx(combobox_ex32, 0, ‘ComboBox‘, None) edit = win32gui.FindWindowEx(combobox, 0, ‘Edit‘, None) # 确定按钮 button = win32gui.FindWindowEx(dialog, 0, ‘Button‘, None) # 在输入框中, 输入绝对路径 win32gui.SendMessage(edit, win32con.WM_SETTEXT, None, file_path) # 点击打开按钮 win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button) break if dialog == 0: log.error("上传文件失败 上传按钮定位: %s 上传文件: %s " % (loc, file_path)) except Exception as err: log.error("上传文件失败: %s %s %s" % (loc, file_path, err)) def switch_frame(self, tag_name, num): """ 切换 frame 标签 :meth tag_name: 元素定位 type: str :meth num: 位置 type: int :return: """ try: ele_list = self.driver.find_elements_by_tag_name(tag_name) self.driver.switch_to.frame(ele_list[num]) except Exception as err: log.error("切换 frame 错误: %s %s" % (tag_name, err)) def exec_script(self, src): """ 用于执行js脚本,返回执行结果 :meth src: js 脚本 type: str :return: """ try: self.driver.execute_script(src) except Exception as err: log.error("执行js脚本错误: %s %s" % (src, err)) def send_keys(self, loc, value, *text_name): """ 重写 send_keys 方法 :meth loc: 元素定位 type: tuple :meth value: 输入值 type: str :meth text_name: 文本框名称 type: tuple :return: """ try: if loc[0] == ‘js‘: self.exec_script(loc[2]) else: # 点击文本框 self.find_element(int(loc[1]), *(loc[0], loc[2].format(text_name))).click() # 清空文本框 self.find_element(int(loc[1]), *(loc[0], loc[2].format(text_name))).clear() # 输入文本值 self.find_element(int(loc[1]), *(loc[0], loc[2].format(text_name))).send_keys(value) except AttributeError as err: log.error("输入文本错误: %s %s" % (loc, err)) def click_button(self, loc, *btn_name): """ 点击操作 :meth loc: 元素定位 type: tuple :meth btn_name: 按钮名称 type: tuple :return: """ try: if loc[0] == ‘js‘: self.exec_script(loc[2]) else: self.find_element(int(loc[1]), *(loc[0], loc[2].format(btn_name))).click() except AttributeError as err: log.error("点击元素错误: %s %s" % (loc, err)) def select_checkbox(self, loc): """ 勾选复选框 :meth loc: 元素定位 type: tuple :return: """ try: if loc[0] == ‘js‘: self.exec_script(loc[2]) else: # 判断复选框是否被勾选 if not self.find_element(int(loc[1]), *(loc[0], loc[2])).is_selected(): self.find_element(int(loc[1]), *(loc[0], loc[2])).click() except Exception as err: log.error("勾选文本框错误: %s %s" % (loc, err)) def mouse_move(self, loc): """ 模拟鼠标悬停 :meth loc: 元素定位 type: tuple :return: """ try: # 鼠标移到悬停元素上 ActionChains(self.driver).move_to_element(self.find_element(int(loc[1]), *(loc[0], loc[2]))).perform() except Exception as err: log.error("鼠标悬停错误: %s %s" % (loc, err)) def select_combobox(self, loc, value): """ 选择下拉框的值, <select>标签下拉菜单 :meth loc: 元素定位 type: tuple :meth value: 选项值 type: str :return: """ try: if loc[0] == ‘js‘: self.exec_script(loc[2]) else: Select(self.find_element(int(loc[1]), *(loc[0], loc[2]))).select_by_value(value) except Exception as err: log.error("选择下拉框错误: %s %s" % (loc, err)) def select_ul(self, select_loc, item_loc, select, item): """ 选择下拉框的值, 非<select>标签下拉菜单 :meth select_loc: 下拉框元素定位 type: tuple :meth item_loc: 选项值元素定位 type: tuple :meth select: 下拉框名称 type: str :meth item: 选项值 type: str :return: """ try: if item_loc[0] == ‘js‘: self.exec_script(item_loc[2]) elif select_loc[0] == ‘js‘: self.exec_script(select_loc[2]) else: loc_sele = (select_loc[0], int(select_loc[1]), select_loc[2].format(select)) self.click_button(loc_sele) loc_val = (item_loc[0], int(item_loc[1]), select_loc[2].format(select, item)) self.click_button(loc_val) # 拖动控件内的滚动条 # self.driver.execute_script("document.getElementsByClassName(‘dropdown-menu inner‘)[1].scrollTop=500;") except Exception as err: log.error("选择下拉框错误: %s, %s %s" % (select_loc, item_loc, err)) def get_attrval(self, loc, value): """ 获取文本框的值 :meth loc: 元素定位 type: tuple :meth value: 文本框的属性名 type: str :return: """ try: if loc[0] == ‘js‘: return self.exec_script(loc[2]) else: return self.find_element(int(loc[1]), *(loc[0], loc[2])).get_attribute(value) except Exception as err: log.error("获取文本框错误: %s %s" % (loc, err)) def get_text(self, loc): """ 获取标签中的文本值 :meth loc: 元素定位 type: tuple :return: """ try: if loc[0] == ‘js‘: return self.exec_script(loc[2]) else: return self.find_element(int(loc[1]), *(loc[0], loc[2])).text except Exception as err: log.error("获取标签中的文本值错误: %s %s" % (loc, err))
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 from selenium import webdriver def get_driver(): """ 无界面运行 """ # 配置浏览器参数 # options = webdriver.ChromeOptions() # options.add_argument(‘--headless‘) # return webdriver.Chrome(chrome_options=options) """ 图形界面运行 """ return webdriver.Chrome()
读取配置文件
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 import os from configparser import ConfigParser # 项目路径 CUR_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) class Project(object): def __init__(self): self.conf = ConfigParser() # 读取项目的配置文件 self.conf.read(CUR_PATH + "/data/config/project.conf", encoding=‘UTF-8‘) def read_gateway(self): return CUR_PATH + self.conf.get("conf", "gateway") def read_oms(self): return CUR_PATH + self.conf.get("conf", "oms") def read_log(self): """ 读取日志的配置文件 :return: """ return CUR_PATH + self.conf.get("log", "path") class Gateway(object): def __init__(self): self.conf = ConfigParser() # 读取支付网关的配置文件 self.conf.read(Project().read_gateway(), encoding=‘UTF-8‘) def read_link(self): # 读取支付网关登录链接 return self.conf.get("gateway", "login") def read_domain(self, section): """ 读取支付域名名称 :meth section: 支付域名名称 type: str :return: 包含元组的列表 """ return self.conf.items(section) def read_path(self, sec, opt): return CUR_PATH + self.conf.get(sec, opt) def read_val(self, sec, opt): return self.conf.get(sec, opt) if __name__ == ‘__main__‘: val = Gateway().read_domain("domain") print(val)
读取 excel 测试数据(使用 list_in_dict() 方法)
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 import xlrd class ExcelUtils(object): def __init__(self, excel_path, sheet_name): # 打开 excel 文件 self.data = xlrd.open_workbook(excel_path) # 获取指定的 sheet self.sheet = self.data.sheet_by_name(sheet_name) # 获取第一行的值 self.row = self.sheet.row_values(0) # 获取第一列的值 self.col = self.sheet.col_values(0) # excel 表的行数 self.rowNum = self.sheet.nrows # excel 表的列数 self.colNum = self.sheet.ncols # 当前行号 self.curRowNo = 1 def has_next(self): """ 当行数为0或者读取的行数小于行号时, 返回 False :return: True or False type: bool """ if self.rowNum == 0 or self.rowNum <= self.curRowNo: return False else: return True def list_in_dict(self): """ 生成包含字典的列表数据, 第二行数据作为键, 第三行及之后的数据作为值 :return: data_list type: list """ data_list = [] row_val = self.sheet.row_values(1) self.curRowNo += 1 while self.has_next(): data_dict = {} col = self.sheet.row_values(self.curRowNo) skip = 1 for x in range(self.colNum): if row_val[x] == "Skip" and col[x] == "Yes": skip = 0 data_dict.setdefault(row_val[x], col[x]) if skip == 1: data_list.append(data_dict) self.curRowNo += 1 return data_list if __name__ == ‘__main__‘: value = ExcelUtils("../data/testdata/gateway/ThreePay.xlsx", "PayPage").list_in_dict() print(value)
日志
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 import logging import logging.config from common.conf_utils import Project # 日志配置文件 logging.config.fileConfig(Project().read_log()) class Log(object): def __init__(self): # 创建一个日志器 logger self.logger = logging.getLogger("AutoTest") def __console(self, level, message): if level == ‘info‘: self.logger.info(message) elif level == ‘debug‘: self.logger.debug(message) elif level == ‘warning‘: self.logger.warning(message) elif level == ‘error‘: self.logger.error(message, exc_info=True) def debug(self, message): self.__console(‘debug‘, message) def info(self, message): self.__console(‘info‘, message) def warning(self, message): self.__console(‘warning‘, message) def error(self, message): self.__console(‘error‘, message) if __name__ == "__main__": log = Log() log.info("---测试开始----") log.info("操作步骤1,2,3") log.info("----测试结束----")
获取元素定位
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 import xml.etree.ElementTree as Et class XmlUtils(object): def __init__(self, xml_path): # 打开xml文档 self.tree = Et.ElementTree(file=xml_path) # 获得根元素对象 self.root_obj = self.tree.getroot() def get_tag(self): """ 获得根节点名称 :return: type: str """ return self.root_obj.tag def get_attribute(self): """ 获得根节点属性 :return: type: str """ return self.root_obj.attrib def get_attr_by_tag(self, sec_attr, sec_value, third_tag): """ 根据二级标签的 sec_name 遍历此标签下的标签名为 third_tag 的所有属性数据 :meth sec_attr: 二级标签的属性名 type: str :meth sec_value: sec_attr 对应的属性值 type: str :meth third_tag: 三级标签的标签名 type: str :return: third_tag 对应的所有属性数据 type: dict """ data_dict = {} # 遍历 root 的下一层 for next_node in self.root_obj: # 遍历 third_tag 标签的所有数据 if next_node.attrib[sec_attr] == sec_value: for sub_item in next_node.iter(third_tag): data_dict.setdefault(sub_item.text, tuple(sub_item.attrib.values())) return data_dict if __name__ == ‘__main__‘: print(XmlUtils(‘../data/locator/gateway/PayPage.xml‘).get_attr_by_tag("pageName", ‘webpay‘, ‘locator‘))
3、数据文件
项目中配置文件的路径
[gateway] # 测试链接 login = http://192.168.xx.xx:xxxx/Test/ [domain] # 测试支付域名 put_pay = /web/test1 put_standard = /web/test2 put_ncgame = /web/test3 put_safe = /web/test4 put_inst = /web/test5 put_multiple = /web/test6 put_quick = /web/test7 put_ever = /web/test8 put_secure = /web/test9 put_web = /web/test10 put_virtual = /web/test11 put_webbr = /web/test12 put_starcor = /web/test13 [xml] # 页面元素文件路径 home = /data/locator/home/Gateway.xml pay = /data//locator/gateway/PayPage.xml result = /data//locator/gateway/ResultPage.xml threepay = /data/locator/gateway/ThreePay.xml threequick = /data/locator/gateway/ThreeQuick.xml halfpay = /data/locator/gateway/TwoHalfPay.xml halfquick = /data/locator/gateway/TwoHalfQuick.xml twopay = /data/locator/gateway/TwoPay.xml twoquick = /data/locator/gateway/TwoQuick.xml check = /data/locator/gateway/Check.xml [xlsx] # 测试数据文件路径 threepay = /data/testdata/gateway/ThreePay.xlsx threequick = /data/testdata/gateway/ThreeQuick.xlsx halfpay = /data/testdata/gateway/TwoHalfPay.xlsx halfquick = /data/testdata/gateway/TwoHalfQuick.xlsx twopay = /data/testdata/gateway/TwoPay.xlsx twoquick = /data/testdata/gateway/TwoQuick.xlsx check = /data/testdata/gateway/Check.xlsx [addr] thr = /PaymentGateway/test thrcre = /PaymentGateway/test/create thrpay = /PaymentGateway/test/directtest/quick two = /PaymentGateway twocre = /PaymentGateway/test/directtest/create twopay = /PaymentGateway/test/directtest/quick twh = /PaymentGateway/test/indirecttest twhcre = /PaymentGateway/test/directtest/create twhpay = /PaymentGateway/test/directtest/quick check = /test/check/ track = /test/uploadTrackingNo apply_ref = /test/applyRefund query_ref = /test/queryRefund
日志配置
[loggers] keys=root,AutoTest [handlers] keys=fileHandler [formatters] keys=form [logger_root] level=INFO handlers=fileHandler [logger_AutoTest] level=INFO handlers=fileHandler qualname=AutoTest propagate=0 [handler_fileHandler] class=handlers.TimedRotatingFileHandler args=("logs/catalina.log", ‘d‘, 1, 0, ‘utf-8‘) level=INFO formatter=form [formatter_form] format=%(asctime)s - %(name)s - %(levelname)s - %(message)s datefmt= ‘%Y-%m-%d %I:%M:%S %p‘
元素定位
<?xml version="1.0" encoding="UTF-8"?> <map> <!-- 测试页面 --> <page pageName="paythree"> <!--Locator lists --> <locator type="id" timeOut="5" value="suburl">ComboboxAddr</locator> <locator type="id" timeOut="5" value="account">AccountId</locator> <locator type="id" timeOut="5" value="terminal">TerminalId</locator> <locator type="id" timeOut="5" value="order_amount">OrderAmount</locator> <locator type="id" timeOut="5" value="btnAdd">MakePayment</locator> </page> </map>
测试数据
4、日志
‘2018-04-09 08:59:57 AM‘ - AutoTest - INFO - test case path: E:Oceanpayment estcase ‘2018-04-09 08:59:58 AM‘ - AutoTest - INFO - report path: E:Oceanpayment eportTestResult.html ‘2018-04-09 08:59:58 AM‘ - AutoTest - INFO - ----- 开始执行测试用例 ----- ‘2018-04-09 08:59:58 AM‘ - AutoTest - INFO - ----- 启动浏览器 ----- ‘2018-04-09 09:00:04 AM‘ - AutoTest - INFO - 登录-首页 ‘2018-04-09 09:00:05 AM‘ - AutoTest - INFO - 点击 ‘测试‘ 链接 ‘2018-04-09 09:00:06 AM‘ - AutoTest - INFO - ----- 页面标题: 测试 ----- ‘2018-04-09 09:00:06 AM‘ - AutoTest - INFO - 选择提交地址 ‘2018-04-09 09:00:06 AM‘ - AutoTest - INFO - 输入帐号ID ‘2018-04-09 09:00:06 AM‘ - AutoTest - INFO - 输入终端ID ‘2018-04-09 09:00:06 AM‘ - AutoTest - INFO - 点击 make payemnt ‘2018-04-09 09:00:07 AM‘ - AutoTest - INFO - ----- 页面链接: http://xxx/PaymentGateway/test.html;jsessionid=K96jh4bW0tdXCRLkqYPwjSqQPh1MhLq4MppvBXgnlh8y71wGNl21!-1602834038 ----- ‘2018-04-09 09:00:07 AM‘ - AutoTest - INFO - 输入 Card Number ‘2018-04-09 09:00:07 AM‘ - AutoTest - INFO - 选择年月 ‘2018-04-09 09:00:07 AM‘ - AutoTest - INFO - 输入 Secure Code ‘2018-04-09 09:00:07 AM‘ - AutoTest - INFO - 点击 PAY NOW ‘2018-04-09 09:00:08 AM‘ - AutoTest - INFO - 登录测试-首页 ‘2018-04-09 09:00:08 AM‘ - AutoTest - INFO - 点击 ‘测试‘ 链接 ‘2018-04-09 09:00:08 AM‘ - AutoTest - INFO - ----- 页面标题: 测试 ----- ‘2018-04-09 09:00:08 AM‘ - AutoTest - INFO - 选择提交地址 ‘2018-04-09 09:00:08 AM‘ - AutoTest - INFO - 输入帐号ID ‘2018-04-09 09:00:08 AM‘ - AutoTest - INFO - 输入终端ID ‘2018-04-09 09:00:08 AM‘ - AutoTest - INFO - 点击 make payemnt
5、页面操作
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 import datetime from common import basepage from common import xml_utils from common.conf_utils import Gateway # 当前年份的下一年 YEAR = str(datetime.datetime.now().year + 1) # 当前月份 MONTH = ‘0{0}‘.format(datetime.datetime.now().month) # 格式: 月/年 "0119" MON_YEAR = MONTH + YEAR[2:] # 读取 xml 文件 xml_obj = xml_utils.XmlUtils(Gateway().read_path("xml", "pay")) class Pay(basepage.Action): """ 测试页面 """ def __init__(self, selenium_driver): super().__init__(selenium_driver) dict_val = xml_obj.get_attr_by_tag(‘pageName‘, ‘paypage‘, ‘locator‘) # ----- 定位器,通过元素属性定位元素对象 ----- # # CardNumber self.num = dict_val[‘CardNumber‘] # "月份" 下拉框 self.mon = dict_val[‘ComboboxMonth‘] # "年份" 下拉框 self.year = dict_val[‘ComboboxYear‘] # SecureCode self.code = dict_val[‘SecureCode‘] # "PAY_NOW" 按钮 self.pay = dict_val[‘PayNow‘] # ----- 页面操作 ----- # def loc_frame(self): self.switch_frame("iframe", 1) def input_card_number(self, card_number): # 输入 CardNumber self.send_keys(self.num, card_number) def select_card_month(self): # 选择 "月份" 下拉框 self.select_combobox(self.mon, MONTH) def select_card_year(self): # 选择 "年份" 下拉框 self.select_combobox(self.year, YEAR) def input_secure_code(self, secure_code): # 输入 SecureCode self.send_keys(self.code, secure_code) def click_pay_now(self): # 点击 "PAY_NOW" 按钮 self.click_button(self.pay)
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 import pageobj.gateway.pay_page as Pay from common.logger import Log class PayAction(object): def __init__(self, driver): self.driver = driver self.log = Log() def put_pay(self, test_data): # 提交支付 pay_page = Pay.Pay(self.driver) self.log.info("----- 页面链接: %s -----" % self.driver.current_url) if ‘/web/vpay‘ in self.driver.current_url: # 切换 frame pay_page.loc_frame() num = test_data[‘CardNumber‘] self.log.info("输入 Card Number: {}".format(num)) pay_page.input_card_number(num) self.log.info("选择年月") pay_page.select_card_month() pay_page.select_card_year() self.log.info("输入 Secure Code") pay_page.input_secure_code(test_data[‘SecureCode‘]) self.log.info("点击 PAY NOW") pay_page.click_pay_now()
6、测试用例
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2018-04-15 09:00:00 # @Author : Canon # @Link : https://www.python.org # @Version : 3.6.1 import re import unittest import ddt from common.browser import get_driver from common.excel_utils import ExcelUtils as Exc from common.logger import Log from common.conf_utils import Gateway from action.gateway import pay as Pa from action.gateway import threepay as Tp from action.gateway import threequick as Tq from action.gateway import twopay as Twp from action.gateway import twoquick as Twq from action.gateway import twohalfpay as Thp from action.gateway import twohalfquick as Thq from action.gateway import result as Res from action.home.gateway import Home # 日志 log = Log() @ddt.ddt class TestGateway(unittest.TestCase): @classmethod def setUpClass(cls): # 浏览器驱动 cls.driver = get_driver() log.info("----- 启动浏览器 -----") # 浏览器最大化 cls.driver.maximize_window() # 测试地址 cls.addr = "http://xxx/test" # 接口类型 cls.create = "3" cls.pay = "2" @classmethod def tearDownClass(cls): log.info("----- 关闭浏览器 -----") cls.driver.close() def setUp(self): # 获取支付域名列表数据 self.payval = Gateway().read_domain("domain") def tearDown(self): pass @ddt.data(*Exc(Gateway().read_path("xlsx", "threepay"), "PayPage").list_in_dict()) def test_threepay(self, test_data): # 进入 测试 Home(self.driver).enter_three() # 提交 3方支付 addr_thr = self.addr + Gateway().read_val("addr", "thr") Tp.Action(self.driver).put_three(addr_thr, test_data["终端ID"][:6], test_data["终端ID"]) # 信用卡支付 domain = re.findall(r"/w+/w+.", self.driver.current_url)[0].replace(".", "") for val in self.payval: for domain_conf in val[1].split(","): if domain == domain_conf.strip(): getattr(Pa.PayAction(self.driver), val[0])(test_data) break # 断言:测试结果与预期结果对比 self.assertEqual(test_data[‘payment_details‘], Res.Back(self.driver).back_datails()) self.assertEqual(test_data[‘payment_status‘], Res.Back(self.driver).back_status()) if __name__ == "__main__": unittest.main()
7、测试报告
基于 common 公共方法的 HTMLTestRunner.py 生成测试报告
以上是关于python seleniumunittest 及 ddt 数据驱动测试的主要内容,如果未能解决你的问题,请参考以下文章
python优缺点分析及python种类,编码-课堂笔记及课后总结
mac设置python及pip环境变量及安装mysqlclient