action
test_script
util
conf
test_data
log
1 from selenium import webdriver 2 import time 3 from conf.global_var import * 4 from util.find_element_util import * 5 from util.ini_parser import * 6 7 8 # 初始化浏览器 9 def init_browser(browser_name): 10 if browser_name.lower() == "chrome": 11 driver = webdriver.Chrome(CHROME_DRIVER) 12 elif browser_name.lower() == "firefox": 13 driver = webdriver.Firefox(FIREFOX_DRIVER) 14 elif browser_name.lower() == "ie": 15 driver = webdriver.Ie(IE_DRIVER) 16 else: 17 return "Error browser name!" 18 return driver 19 20 21 # 访问指定url 22 def visit(driver, url): 23 driver.get(url) 24 25 26 # 输入操作 27 def input(driver, locate_method, locate_exp, value): 28 # 方式1:直接传定位方式和定位表达式 29 if locate_method in ["id", "xpath", "classname", "name", "tagname", "linktext", 30 "partial link text", "css selector"]: 31 find_element(driver, locate_method, locate_exp).send_keys(value) 32 # 方式2:通过ini文件的key找到value,再分割定位方式和定位表达式 33 else: 34 parser = IniParser(ELEMENT_FILE_PATH) 35 locate_method, locate_exp = tuple(parser.get_value(locate_method, locate_exp).split(">")) 36 find_element(driver, locate_method, locate_exp).send_keys(value) 37 38 39 # 点击操作 40 def click(driver, locate_method, locate_exp): 41 # 方式1:直接传定位方式和定位表达式 42 if locate_method in ["id", "xpath", "classname", "name", "tagname", "linktext", 43 "partial link text", "css selector"]: 44 find_element(driver, locate_method, locate_exp).click() 45 # 方式2:通过ini文件的key找到value,再分割定位方式和定位表达式 46 else: 47 parser = IniParser(ELEMENT_FILE_PATH) 48 locate_method, locate_exp = tuple(parser.get_value(locate_method, locate_exp).split(">")) 49 find_element(driver, locate_method, locate_exp).click() 50 51 52 # 清空输入框操作 53 def clear(driver, locate_method, locate_exp): 54 # 方式1:直接传定位方式和定位表达式 55 if locate_method in ["id", "xpath", "classname", "name", "tagname", "linktext", 56 "partial link text", "css selector"]: 57 find_element(driver, locate_method, locate_exp).clear() 58 # 方式2:通过ini文件的key找到value,再分割定位方式和定位表达式 59 else: 60 parser = IniParser(ELEMENT_FILE_PATH) 61 locate_method, locate_exp = tuple(parser.get_value(locate_method, locate_exp).split(">")) 62 find_element(driver, locate_method, locate_exp).clear() 63 64 65 # 切换frame 66 def switch_frame(driver, locate_method, locate_exp): 67 # 方式1:直接传定位方式和定位表达式 68 if locate_method in ["id", "xpath", "classname", "name", "tagname", "linktext", 69 "partial link text", "css selector"]: 70 driver.switch_to.frame(find_element(driver, locate_method, locate_exp)) 71 # 方式2:通过ini文件的key找到value,再分割定位方式和定位表达式 72 else: 73 parser = IniParser(ELEMENT_FILE_PATH) 74 locate_method, locate_exp = tuple(parser.get_value(locate_method, locate_exp).split(">")) 75 driver.switch_to.frame(find_element(driver, locate_method, locate_exp)) 76 77 78 # 切换主frame 79 def switch_home_frame(driver): 80 driver.switch_to.default_content() 81 82 83 # 断言 84 def assert_word(driver, keyword): 85 assert keyword in driver.page_source 86 87 88 # 休眠 89 def sleep(driver, times): 90 time.sleep(int(times)) 91 92 93 # 关闭浏览器 94 def quit(driver): 95 driver.quit() 96 97 98 if __name__ == "__main__": 99 driver = init_browser("chrome") 100 visit(driver, "http://mail.126.com") 101 switch_frame(driver, "xpath", "//iframe[contains(@id,‘x-URS-iframe‘)]") 102 clear(driver, "xpath", "//input[@name=‘email‘]") 103 input(driver, "xpath", "//input[@name=‘email‘]", "juno3550") 104 input(driver, "xpath", "//input[@name=‘password‘]", "258978aa") 105 click(driver, "id", "dologin") 106 sleep(driver, 2) 107 assert_word(driver, "退出") 108 # 通过配置文件传参 109 quit(driver) 110 driver = init_browser("chrome") 111 visit(driver, "http://mail.126.com") 112 switch_frame(driver, "126mail_indexPage", "indexPage.frame") 113 clear(driver, "126mail_indexPage", "indexPage.username") 114 input(driver, "126mail_indexPage", "indexPage.username", "xxx") 115 input(driver, "126mail_indexPage", "indexPage.password", "xxx") 116 click(driver, "126mail_indexPage", "indexPage.loginbutton") 117 sleep(2) 118 assert_word(driver, "退出") 119 quit(driver)
1 import traceback 2 import re 3 import queue 4 import threading 5 from action.keyword import * 6 from util.excel_util import Excel 7 from util.screenshot import take_screenshot 8 from util.datetime_util import * 9 from util.log_util import * 10 11 12 # 测试步骤sheet用例的执行函数 13 def execute_case(driver, test_data_file_path, test_script_sheet_name, test_data, head_flag=True): 14 """ 15 :param driver: selenium的driver对象 16 :param test_data_file_path: 测试数据excel文件名称 或 excel实例化对象 17 :param test_script_sheet_name: 测试步骤的sheet名称 18 :param test_data: 测试数据sheet中的指定行数据,格式如[{"登录用户名": "xxx", "登录密码": "xxx", ...}, {...}, ...] 19 :param head_flag: 是否在测试结果sheet中写入标题行,默认只写入一次标题行 20 :return: 指定行的用例/用例集的执行结果 21 """ 22 case_suite_result = "成功" 23 # 如果传入的是excel对象,则无需再次初始化;多次初始化会导致后续写入失败 24 if isinstance(test_data_file_path, Excel): 25 excel = test_data_file_path 26 # 初始化excel工具类对象 27 else: 28 excel = Excel(test_data_file_path) 29 excel.change_sheet(test_script_sheet_name) 30 all_row_data = excel.get_all_row_data() 31 excel.change_sheet("测试结果") 32 # 在测试结果sheet中,标题行仅写入一次 33 if head_flag: 34 excel.write_row_data(all_row_data[0], "red") 35 # 除标题行外,遍历所有行数据 36 for row_data in all_row_data[1:]: 37 # 若某行用例是其他sheet的用例集,则先递归执行完其他sheet的用例 38 if "other_test_cases" in row_data[TEST_SCRIPT_KEYWORD_COL]: 39 case_result = execute_case(driver, excel, row_data[TEST_SCRIPT_VALUE_COL], test_data, False) 40 else: 41 keyword = row_data[TEST_SCRIPT_KEYWORD_COL] 42 locate_method = row_data[TEST_SCRIPT_LOCATE_METHOD_COL] 43 locate_exp = row_data[TEST_SCRIPT_LOCATE_EXP_COL] 44 value = row_data[TEST_SCRIPT_VALUE_COL] 45 # 数据驱动,将${}格式的值替换为数据集(test_data)中的数据进行执行 46 if re.search(r"\$\{(.*)\}", str(value)): 47 key = re.search(r"\$\{(.*)\}", str(value)).group(1) 48 # 如[{"登录用户名": "xxx", "登录密码": "xxx", ...}, {...}, ...] 49 value = test_data[key] 50 # 在测试结果sheet中,也要将${}格式的值替换为数据集(test_data)中的数据 51 row_data[TEST_SCRIPT_VALUE_COL] = value 52 # 存在4种关键字执行函数类型 53 if locate_method and locate_exp: 54 if value: 55 command = "{}(driver, ‘{}‘, ‘{}‘, ‘{}‘)".format(keyword, locate_method, locate_exp, value) 56 else: 57 command = "{}(driver, ‘{}‘, ‘{}‘)".format(keyword, locate_method, locate_exp) 58 else: 59 if value: 60 command = "{}(driver, ‘{}‘)".format(keyword, value) 61 else: 62 command = "{}(driver)".format(keyword) 63 try: 64 # 执行关键字函数用例 65 eval(command) 66 info("用例执行成功:{}".format(command)) 67 case_result = "成功" 68 except: 69 error("用例执行失败:{}".format(command)) 70 traceback.print_exc() 71 # 写入本用例的执行结果 72 case_result = "失败" 73 # 写入本用例集的执行结果 74 case_suite_result = "失败" 75 # 进行截图 76 screenshot_file_path = take_screenshot(driver) 77 # 截图路径记录 78 row_data[TEST_SCRIPT_SCREENSHOT_PATH_COL] = screenshot_file_path 79 # 异常信息记录 80 row_data[TEST_SCRIPT_EXCEPTION_INFO_COL] = traceback.format_exc() 81 # 测试时间记录 82 row_data[TEST_SCRIPT_TEST_TIME_COL] = get_english_datetime() 83 # 测试结果记录 84 row_data[TEST_SCRIPT_TEST_RESULT_COL] = case_result 85 # 将测试结果写入excel 86 excel.write_row_data(row_data) 87 excel.save() 88 # 返回测试集合的测试结果(只要有一条用例不通过,整个测试集合均不通过) 89 return case_suite_result 90 91 92 # 获取测试数据的执行函数 93 # 每行数据作为一个字典,存储在一个列表中。如[{"登录用户名": "xxx", "登录密码": "xxx", ...}, {...}, ...] 94 def get_dict_test_data(test_data_file_path, test_data_sheet_name): 95 """ 96 :param test_data_file_path: 测试数据excel文件名称 或 excel实例化对象 97 :param test_data_sheet_name: 测试数据的sheet名称 98 :return: 测试数据sheet中的所有数据行,格式为{标题: 值} 99 """ 100 # 如果传入的是excel对象,则无需再次初始化 101 if isinstance(test_data_file_path, Excel): 102 excel = test_data_file_path 103 else: 104 excel = Excel(test_data_file_path) 105 excel.change_sheet(test_data_sheet_name) 106 result = [] 107 all_row_data = excel.get_all_row_data() 108 keys = all_row_data[0] 109 for row_data in all_row_data[1:]: 110 dict = {} 111 for i in range(len(keys)): 112 dict[keys[i]] = row_data[i] 113 result.append(dict) 114 return result 115 116 117 # 混合驱动用例的执行函数 118 # 测试步骤sheet与测试数据sheet分离(封装基础用例执行函数与获取测试数据执行函数) 119 def mix_case_execute(browser_name, test_data_file_path, test_script_sheet_name, 120 test_data_sheet_name=None, head_flag=True): 121 """ 122 :param browser_name: 需要初始化的浏览器名称 123 :param test_data_file_path: 测试数据excel文件名称 或 excel实例化对象 124 :param test_script_sheet_name: 测试步骤的sheet名称 125 :param test_data_sheet_name: 测试数据的sheet名称 126 :param head_flag: 是否在测试结果sheet中写入标题行,默认只写入一次标题行 127 :return: 指定行的用例/用例集的执行结果 128 """ 129 case_result = "成功" 130 if test_data_sheet_name: 131 test_data = get_dict_test_data(test_data_file_path, test_data_sheet_name) 132 for data in test_data: 133 info("测试用例数据:{}".format(data)) 134 driver = init_browser(browser_name) 135 result = execute_case(driver, test_data_file_path, test_script_sheet_name, data, head_flag) 136 if result == "失败": 137 case_result = "失败" 138 else: 139 driver = init_browser(browser_name) 140 result = execute_case(driver, test_data_file_path, test_script_sheet_name, None, head_flag) 141 if result == "失败": 142 case_result = "失败" 143 return case_result 144 145 146 # 封装混合驱动用例的执行函数 147 # 测试步骤sheet与测试数据sheet由主测试用例sheet提供 148 def main_case_execute(test_data_file_path, main_case_sheet_name): 149 """ 150 :param test_data_file_path: 测试数据excel文件名称 151 :param main_case_sheet_name: 测试用例的主sheet名称 152 :return: None 153 """ 154 excel = Excel(test_data_file_path) 155 excel.change_sheet(main_case_sheet_name) 156 all_row_data = excel.get_all_row_data() 157 for row_data in all_row_data[1:]: 158 if row_data[MAIN_CASE_IS_EXECUTE_COL].lower() == "y": 159 case_name = row_data[MAIN_CASE_CASE_NAME_COL] 160 info("开始执行测试用例集【{}】".format(case_name)) 161 if row_data[MAIN_CASE_DATA_SHEET_COL]: 162 test_result = mix_case_execute(row_data[MAIN_CASE_BROWSER_NAME_COL], excel, 163 row_data[MAIN_CASE_SCRIPT_SHEET_COL], row_data[MAIN_CASE_DATA_SHEET_COL]) 164 else: 165 test_result = mix_case_execute(row_data[MAIN_CASE_BROWSER_NAME_COL], excel, 166 row_data[MAIN_CASE_SCRIPT_SHEET_COL], row_data[MAIN_CASE_DATA_SHEET_COL]) 167 else: 168 continue 169 excel.change_sheet("测试结果") 170 excel.write_row_data(all_row_data[0], "red") 171 row_data[MAIN_CASE_TEST_TIME_COL] = get_english_datetime() 172 row_data[MAIN_CASE_TEST_RESULT_COL] = test_result 173 excel.write_row_data(row_data) 174 excel.save() 175 176 177 # 多线程任务函数: 178 def thread_task(q): 179 """ 180 :param q: 队列(存储的是测试数据文件) 181 :return: None 182 """ 183 try: 184 if not isinstance(q, queue.Queue): 185 warning("多线程任务函数入参有误:需为队列对象!") 186 return 187 while q.qsize() > 0: 188 test_data_file, main_case_sheet = q.get() 189 main_case_execute(test_data_file, main_case_sheet) 190 except: 191 error("多线程任务函数执行异常!") 192 traceback.print_exc() 193 194 195 # 多线程执行函数 196 def thread_main(thread_data, thread_num): 197 """ 198 :param thread_data: 多线程任务函数所需要的测试数据集(二维数组)参数 199 :param thread_num: 需要开启的线程数 200 :return: None 201 """ 202 try: 203 if not isinstance(thread_data, list): 204 warning("多线程任务函数入参有误:需为数组对象!") 205 return 206 for li in thread_data: 207 if not isinstance(li, list): 208 warning("多线程任务函数入参有误:需为二维数组对象!") 209 return 210 if not (isinstance(thread_num, int) and thread_num > 0): 211 warning("多线程任务函数入参有误:需为正整数对象!") 212 return 213 q = queue.Queue() 214 for data in thread_data: 215 q.put(tuple(data)) 216 thread_list = [] 217 # 初始化多线程 218 for i in range(thread_num): 219 t = threading.Thread(target=thread_task, args=(q,)) 220 thread_list.append(t) 221 # 启动多线程 222 for t in thread_list: 223 t.start() 224 # 等待所有子线程结束 225 for t in thread_list: 226 t.join() 227 except: 228 error("多线程执行函数执行异常!") 229 traceback.print_exc() 230 231 232 if __name__ == "__main__": 233 # 基础用例的执行函数 234 # execute_case(driver, TEST_DATA_FILE_PATH_1, "添加联系人1") 235 # 获取测试数据的执行函数,如[{"登录用户名": "xxx", "登录密码": "xxx", ...}, {...}, ...] 236 # print(get_dict_test_data(TEST_DATA_FILE_PATH_1, "联系人数据")) 237 # 混合驱动用例的执行函数,测试步骤sheet与测试数据sheet分离(封装基础用例执行函数与获取测试数据执行函数) 238 # mix_case_execute("chrome", TEST_DATA_FILE_PATH_1, "添加联系人", "联系人数据") 239 # 封装混合驱动用例的执行函数,测试步骤sheet与测试数据sheet由主测试用例sheet提供 240 # main_case_execute(TEST_DATA_FILE_PATH_1, "测试用例") 241 # 多线程任务函数所需的数据集合 242 thread_data = [[TEST_DATA_FILE_PATH_1, "测试用例"], [TEST_DATA_FILE_PATH_2, "测试用例"], 243 [TEST_DATA_FILE_PATH_3, "测试用例"]] 244 # 多线程执行函数 245 thread_main(thread_data, 3)
1 from selenium.webdriver.support.ui import WebDriverWait 2 3 4 # 显式等待一个元素 5 def find_element(driver, locate_method, locate_exp): 6 # 显式等待对象(最多等10秒,每0.2秒判断一次等待的条件) 7 return WebDriverWait(driver, 10, 0.2).until(lambda x: x.find_element(locate_method, locate_exp)) 8 9 # 显式等待一组元素 10 def find_elements(driver, locate_method, locate_exp): 11 # 显式等待对象(最多等10秒,每0.2秒判断一次等待的条件) 12 return WebDriverWait(driver, 10, 0.2).until(lambda x: x.find_elements(locate_method, locate_exp))
1 from openpyxl import load_workbook 2 from openpyxl.styles import PatternFill, Font, Side, Border 3 import os 4 5 6 class Excel: 7 8 def __init__(self, test_data_file_path): 9 # 文件格式校验 10 if not os.path.exists(test_data_file_path): 11 print("Excel工具类初始化失败:【{}】文件不存在!".format(test_data_file_path)) 12 return 13 if not test_data_file_path.endswith(".xlsx") or not test_data_file_path.endswith(".xlsx"): 14 print("Excel工具类初始化失败:【{}】文件非excel文件类型!".format(test_data_file_path)) 15 return 16 # 打开指定excel文件 17 self.wb = load_workbook(test_data_file_path) 18 # 初始化默认sheet 19 self.ws = self.wb.active 20 # 保存文件时使用的文件路径 21 self.test_data_file_path = test_data_file_path 22 # 初始化红、绿色,供样式使用 23 self.color_dict = {"red": "FFFF3030", "green": "FF008B00"} 24 25 # 查看所有sheet名称 26 def get_sheets(self): 27 return self.wb.sheetnames 28 29 # 根据sheet名称切换sheet 30 def change_sheet(self, sheet_name): 31 if sheet_name not in self.get_sheets(): 32 print("sheet切换失败:【{}】指定sheet名称不存在!".format(sheet_name)) 33 return 34 self.ws = self.wb.get_sheet_by_name(sheet_name) 35 36 # 返回当前sheet的最大行号 37 def max_row_num(self): 38 return self.ws.max_row 39 40 # 返回当前sheet的最大列号 41 def max_col_num(self): 42 return self.ws.max_column 43 44 # 获取指定行数据(设定索引从0开始) 45 def get_one_row_data(self, row_no): 46 if row_no < 0 or row_no > self.max_row_num()-1: 47 print("输入的行号【{}】有误:需在0至最大行数之间!".format(row_no)) 48 return 49 # API的索引从1开始 50 return [cell.value for cell in self.ws[row_no+1]] 51 52 # 获取指定列数据 53 def get_one_col_data(self, col_no): 54 if col_no < 0 or col_no > self.max_col_num()-1: 55 print("输入的列号【{}】有误:需在0至最大列数之间!".format(col_no)) 56 return 57 return [cell.value for cell in tuple(self.ws.columns)[col_no+1]] 58 59 # 获取当前sheet的所有行数据 60 def get_all_row_data(self): 61 result = [] 62 # # API的索引从1开始 63 for row_data in self.ws[1:self.max_row_num()]: 64 result.append([cell.value for cell in row_data]) 65 return result 66 67 # 追加一行数据 68 def write_row_data(self, data, fill_color=None, font_color=None, border=True): 69 if not isinstance(data, (list, tuple)): 70 print("追加的数据类型有误:需为列号或元组类型!【{}】".format(data)) 71 return 72 self.ws.append(data) 73 # 添加字体颜色 74 if font_color: 75 if font_color in self.color_dict.keys(): 76 font_color = self.color_dict[font_color] 77 # 需要设置的单元格长度应与数据长度一致,否则默认与之前行的长度一致 78 count = 0 79 for cell in self.ws[self.max_row_num()]: 80 if count > len(data) - 1: 81 break 82 # cell不为None,才能设置样式 83 if cell: 84 if cell.value in ["pass", "成功"]: 85 cell.font = Font(color=self.color_dict["green"]) 86 elif cell.value in ["fail", "失败"]: 87 cell.font = Font(color=self.color_dict["red"]) 88 else: 89 cell.font = Font(color=font_color) 90 count += 1 91 # 添加背景颜色 92 if fill_color: 93 if fill_color in self.color_dict.keys(): 94 fill_color = self.color_dict[fill_color] 95 count = 0 96 for cell in self.ws[self.max_row_num()]: 97 if count > len(data) - 1: 98 break 99 if cell: 100 cell.fill = PatternFill(fill_type="solid", fgColor=fill_color) 101 count += 1 102 # 添加单元格边框 103 if border: 104 bd = Side(style="thin", color="000000") 105 count = 0 106 for cell in self.ws[self.max_row_num()]: 107 if count > len(data) - 1: 108 break 109 if cell: 110 cell.border = Border(left=bd, right=bd, top=bd, bottom=bd) 111 count += 1 112 113 # 保存文件 114 def save(self): 115 self.wb.save(self.test_data_file_path) 116 117 118 if __name__ == "__main__": 119 from conf.global_var import * 120 excel = Excel(TEST_DATA_FILE_PATH) 121 excel.change_sheet("登录1") 122 # print(excel.get_all_row_data()) 123 excel.write_row_data((1,2,"嘻哈",None,"ddd"), "red", "green") 124 excel.save()
1 import configparser 2 3 4 class IniParser: 5 6 # 初始化打开指定ini文件并指定编码 7 def __init__(self, file_path): 8 self.cf = configparser.ConfigParser() 9 self.cf.read(file_path, encoding="utf-8") 10 11 # 获取所有分组名称 12 def get_sections(self): 13 return self.cf.sections() 14 15 # 获取指定分组的所有键 16 def get_options(self, section): 17 return self.cf.options(section) 18 19 # 获取指定分组的键值对 20 def get_items(self, section): 21 return self.cf.items(section) 22 23 # 获取指定分组的指定键的值 24 def get_value(self, section, key): 25 return self.cf.get(section, key) 26 27 28 if __name__ == "__main__": 29 from conf.global_var import * 30 parser = IniParser(ELEMENT_FILE_PATH) 31 print(parser.get_sections()) 32 print(parser.get_options("126mail_indexPage")) 33 print(parser.get_value("126mail_indexPage", ‘indexpage.frame‘))
1 import time 2 3 4 # 返回中文格式的日期:xxxx年xx月xx日 5 def get_chinese_date(): 6 year = time.localtime().tm_year 7 if len(str(year)) == 1: 8 year = "0" + str(year) 9 month = time.localtime().tm_mon 10 if len(str(month)) == 1: 11 month = "0" + str(month) 12 day = time.localtime().tm_mday 13 if len(str(day)) == 1: 14 day = "0" + str(day) 15 return "{}年{}月{}日".format(year, month, day) 16 17 18 # 返回英文格式的日期:xxxx/xx/xx 19 def get_english_date(): 20 year = time.localtime().tm_year 21 if len(str(year)) == 1: 22 year = "0" + str(year) 23 month = time.localtime().tm_mon 24 if len(str(month)) == 1: 25 month = "0" + str(month) 26 day = time.localtime().tm_mday 27 if len(str(day)) == 1: 28 day = "0" + str(day) 29 return "{}/{}/{}".format(year, month, day) 30 31 32 # 返回中文格式的时间:xx时xx分xx秒 33 def get_chinese_time(): 34 hour = time.localtime().tm_hour 35 if len(str(hour)) == 1: 36 hour = "0" + str(hour) 37 minute = time.localtime().tm_min 38 if len(str(minute)) == 1: 39 minute = "0" + str(minute) 40 second = time.localtime().tm_sec 41 if len(str(second)) == 1: 42 second = "0" + str(second) 43 return "{}时{}分{}秒".format(hour, minute, second) 44 45 46 # 返回英文格式的时间:xx:xx:xx 47 def get_english_time(): 48 hour = time.localtime().tm_hour 49 if len(str(hour)) == 1: 50 hour = "0" + str(hour) 51 minute = time.localtime().tm_min 52 if len(str(minute)) == 1: 53 minute = "0" + str(minute) 54 second = time.localtime().tm_sec 55 if len(str(second)) == 1: 56 second = "0" + str(second) 57 return "{}:{}:{}".format(hour, minute, second) 58 59 60 # 返回中文格式的日期时间 61 def get_chinese_datetime(): 62 return get_chinese_date() + " " + get_chinese_time() 63 64 65 # 返回英文格式的日期时间 66 def get_english_datetime(): 67 return get_english_date() + " " + get_english_time() 68 69 70 if __name__ == "__main__": 71 print(get_chinese_datetime()) 72 print(get_english_datetime())
1 import logging 2 import logging.config 3 from conf.global_var import * 4 5 6 # 日志配置文件:多个logger,每个logger指定不同的handler 7 # handler:设定了日志输出行的格式 8 # 以及设定写日志到文件(是否回滚)?还是到屏幕 9 # 还定了打印日志的级别 10 logging.config.fileConfig(LOG_CONF_FILE_PATH) 11 logger = logging.getLogger("example01") 12 13 14 def debug(message): 15 logging.debug(message) 16 17 18 def info(message): 19 logging.info(message) 20 21 22 def warning(message): 23 logging.warning(message) 24 25 26 def error(message): 27 logging.error(message) 28 29 30 if __name__=="__main__": 31 debug("hi") 32 info("hiphop") 33 warning("hello") 34 error("这是一个error日志")
1 import traceback 2 import os 3 from util.datetime_util import * 4 from conf.global_var import * 5 6 7 # 截图函数 8 def take_screenshot(driver): 9 # 创建当前日期目录 10 dir = os.path.join(SCREENSHOT_PATH, get_chinese_date()) 11 if not os.path.exists(dir): 12 os.makedirs(dir) 13 # 以当前时间为文件名 14 file_name = get_chinese_time() 15 file_path = os.path.join(dir, file_name+".png") 16 try: 17 driver.get_screenshot_as_file(file_path) 18 # 返回截图文件的绝对路径 19 return file_path 20 except: 21 print("截图发生异常【{}】".format(file_path)) 22 traceback.print_exc() 23 return file_path
1 import os 2 3 4 # 工程根路径 5 PROJECT_ROOT_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 6 7 # 元素定位方法的ini配置文件路径 8 ELEMENT_FILE_PATH = os.path.join(PROJECT_ROOT_PATH, "conf", "ElementsRepository.ini") 9 10 # excel文件路径 11 TEST_DATA_FILE_PATH_1 = os.path.join(PROJECT_ROOT_PATH, "test_data", "混合驱动_测试用例_1.xlsx") 12 TEST_DATA_FILE_PATH_2 = os.path.join(PROJECT_ROOT_PATH, "test_data", "混合驱动_测试用例_2.xlsx") 13 TEST_DATA_FILE_PATH_3 = os.path.join(PROJECT_ROOT_PATH, "test_data", "混合驱动_测试用例_3.xlsx") 14 15 # 驱动路径 16 CHROME_DRIVER = "E:\\auto_test_driver\\chromedriver.exe" 17 IE_DRIVER = "E:\\auto_test_driver\\IEDriverServer.exe" 18 FIREFOX_DRIVER = "E:\\auto_test_driver\\geckodriver.exe" 19 20 # 截图路径 21 SCREENSHOT_PATH = os.path.join(PROJECT_ROOT_PATH, "screenshot_path") 22 23 # 日志配置文件路径 24 LOG_CONF_FILE_PATH = os.path.join(PROJECT_ROOT_PATH, "conf", "Logger.conf") 25 26 # 测试步骤sheet的列号 27 TEST_SCRIPT_KEYWORD_COL = 2 28 TEST_SCRIPT_LOCATE_METHOD_COL = 3 29 TEST_SCRIPT_LOCATE_EXP_COL = 4 30 TEST_SCRIPT_VALUE_COL = 5 31 TEST_SCRIPT_TEST_TIME_COL = 6 32 TEST_SCRIPT_TEST_RESULT_COL = 7 33 TEST_SCRIPT_EXCEPTION_INFO_COL = 8 34 TEST_SCRIPT_SCREENSHOT_PATH_COL = 9 35 36 # 主测试用例sheet列号 37 MAIN_CASE_CASE_NAME_COL = 3 38 MAIN_CASE_BROWSER_NAME_COL = 5 39 MAIN_CASE_SCRIPT_SHEET_COL = 6 40 MAIN_CASE_DATA_SHEET_COL = 7 41 MAIN_CASE_IS_EXECUTE_COL = 8 42 MAIN_CASE_TEST_TIME_COL = 9 43 MAIN_CASE_TEST_RESULT_COL = 10 44 45 46 if __name__ == "__main__": 47 print(PROJECT_ROOT_PATH)
1 [126mail_indexPage] 2 indexPage.loginlink=xpath>//a[contains(text(),‘密码登录‘)] 3 indexPage.frame=xpath>//iframe[contains(@id,‘x-URS-iframe‘)] 4 indexPage.username=xpath>//input[@name=‘email‘] 5 indexPage.password=xpath>//input[@name=‘password‘] 6 indexPage.loginbutton=id>dologin 7 8 [126mail_homePage] 9 homePage.addressLink=xpath>//div[text()=‘通讯录‘] 10 11 [126mail_contactPersonPage] 12 contactPersonPage.createButton=xpath>//span[text()=‘新建联系人‘] 13 contactPersonPage.name=xpath>//a[@title=‘编辑详细姓名‘]/preceding-sibling::div/input 14 contactPersonPage.email=xpath>//*[@id=‘iaddress_MAIL_wrap‘]//input 15 contactPersonPage.starContacts=xpath>//span[text()=‘设为星标联系人‘]/preceding-sibling::span/b 16 contactPersonPage.phone=xpath>//*[@id=‘iaddress_TEL_wrap‘]//dd//input 17 contactPersonPage.otherinfo=xpath>//textarea 18 contactPersonPage.confirmButton=xpath>//span[.=‘确 定‘]
1 #logger.conf 2 ############################################### 3 [loggers] 4 keys=root,example01,example02 5 [logger_root] 6 level=DEBUG 7 handlers=hand01,hand02 8 9 [logger_example01] 10 handlers=hand01,hand02 11 qualname=example01 12 propagate=0 13 14 [logger_example02] 15 handlers=hand01,hand03 16 qualname=example02 17 propagate=0 18 19 ############################################### 20 [handlers] 21 keys=hand01,hand02,hand03 22 23 [handler_hand01] 24 class=StreamHandler 25 level=INFO 26 formatter=form01 27 args=(sys.stderr,) 28 29 [handler_hand02] 30 class=FileHandler 31 level=DEBUG 32 formatter=form01 33 args=(‘..\\log\\Mail126TestLogfile.log‘, ‘a‘) 34 35 [handler_hand03] 36 class=handlers.RotatingFileHandler 37 level=INFO 38 formatter=form01 39 args=(‘..\\log\\Mail126TestLogfile.log‘, ‘a‘, 10*1024*1024, 5) 40 41 ############################################### 42 [formatters] 43 keys=form01,form02 44 45 [formatter_form01] 46 format=%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s 47 datefmt=%Y-%m-%d %H:%M:%S 48 49 [formatter_form02] 50 format=%(name)-12s: %(levelname)-8s %(message)s 51 datefmt=%Y-%m-%d %H:%M:%S
(供测试步骤sheet的值使用)
(分别打印主测试用例和测试步骤用例的测试结果)
(异常截图保存目录)
(日志输出文件)
2021-02-21 00:20:56 log_util.py[line:19] INFO 开始执行测试用例集【登录流程】 2021-02-21 00:21:07 log_util.py[line:19] INFO 用例执行成功:visit(driver, ‘https://www.126.com‘) 2021-02-21 00:21:07 log_util.py[line:19] INFO 用例执行成功:switch_frame(driver, ‘126mail_indexPage‘, ‘indexPage.frame‘) 2021-02-21 00:21:08 log_util.py[line:19] INFO 用例执行成功:clear(driver, ‘126mail_indexPage‘, ‘indexPage.username‘) 2021-02-21 00:21:08 log_util.py[line:19] INFO 用例执行成功:input(driver, ‘126mail_indexPage‘, ‘indexPage.username‘, ‘xxx‘) 2021-02-21 00:21:09 log_util.py[line:19] INFO 用例执行成功:input(driver, ‘126mail_indexPage‘, ‘indexPage.password‘, ‘xxx‘) 2021-02-21 00:21:09 log_util.py[line:19] INFO 用例执行成功:click(driver, ‘126mail_indexPage‘, ‘indexPage.loginbutton‘) 2021-02-21 00:21:09 log_util.py[line:19] INFO 用例执行成功:switch_home_frame(driver) 2021-02-21 00:21:12 log_util.py[line:19] INFO 用例执行成功:sleep(driver, ‘3‘) 2021-02-21 00:21:13 log_util.py[line:19] INFO 用例执行成功:assert_word(driver, ‘退出‘) 2021-02-21 00:21:17 log_util.py[line:19] INFO 用例执行成功:quit(driver) 2021-02-21 00:21:18 log_util.py[line:19] INFO 开始执行测试用例集【联系人添加流程】 2021-02-21 00:21:18 log_util.py[line:19] INFO 测试用例数据:{‘登录用户名‘: ‘xxx‘, ‘登录密码‘: ‘xxx‘, ‘名字‘: ‘张三‘, ‘邮件地址‘: ‘zhangsan@qq.com‘, ‘电话‘: 13301111111, ‘其他信息‘: ‘张三的信息‘} 2021-02-21 00:21:28 log_util.py[line:19] INFO 用例执行成功:visit(driver, ‘https://www.126.com‘) 2021-02-21 00:21:29 log_util.py[line:19] INFO 用例执行成功:switch_frame(driver, ‘126mail_indexPage‘, ‘indexPage.frame‘) 2021-02-21 00:21:29 log_util.py[line:19] INFO 用例执行成功:clear(driver, ‘126mail_indexPage‘, ‘indexPage.username‘) 2021-02-21 00:21:30 log_util.py[line:19] INFO 用例执行成功:input(driver, ‘126mail_indexPage‘, ‘indexPage.username‘, ‘xxx‘) ...... ......
原文:https://www.cnblogs.com/juno3550/p/14431902.html