自动化测试框架
Posted testyuz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自动化测试框架相关的知识,希望对你有一定的参考价值。
1 # 日志类的封装 2 import logging 3 from logging.handlers import RotatingFileHandler 4 from class_13_0111_rewrite_unittest.config_handle import do_config 5 6 7 class HandleLog: 8 """ 9 日志类的封装 10 """ 11 def __init__(self): 12 self.case_logger = logging.getLogger(do_config(‘log‘, ‘logger_name‘)) 13 self.case_logger.setLevel(do_config(‘log‘, ‘logger_level‘)) 14 console_handle = logging.StreamHandler() 15 file_handle = RotatingFileHandler(filename=do_config(‘log‘, ‘log_filename‘), 16 maxBytes=do_config(‘log‘, ‘maxBytes‘), 17 backupCount=do_config(‘log‘, ‘backupCount‘), 18 encoding=‘utf-8‘) 19 console_handle.setLevel(do_config(‘log‘, ‘console_level‘)) 20 file_handle.setLevel(do_config(‘log‘, ‘file_level‘)) 21 simple_formatter = logging.Formatter(do_config(‘log‘, ‘simple_formatter‘)) 22 verbose_formatter = logging.Formatter(do_config(‘log‘, ‘verbose_formatter‘)) 23 console_handle.setFormatter(simple_formatter) 24 file_handle.setFormatter(verbose_formatter) 25 self.case_logger.addHandler(console_handle) 26 self.case_logger.addHandler(file_handle) 27 28 def get_logger(self): 29 """ 30 获取 logger 日志器对象 31 :return: 32 """ 33 return self.case_logger 34 35 36 do_log = HandleLog().get_logger() 37 38 39 if __name__ == ‘__main__‘: 40 for _ in range(1000): 41 do_log.debug(‘这是 debug 级别的日志。‘) 42 do_log.info(‘这是 info 级别的日志。‘) 43 do_log.warning(‘这是 warning 级别的日志。‘) 44 do_log.error(‘这是 error 级别的日志。‘) 45 do_log.critical(‘这是 critical 级别的日志。‘)
1 # excel 封装成类 2 from openpyxl import load_workbook 3 from collections import namedtuple 4 from class_13_0111_rewrite_unittest.config_handle import do_config 5 6 7 class HandleExcel(object): 8 """ 9 定义处理 excel 的类 10 """ 11 # config = HandleConfig() # 定义一个类属性,创建 HandleConfig() 对象 12 13 def __init__(self, filename, sheetname=None): 14 self.filename = filename 15 self.sheetname = sheetname 16 # 定义一个空列表,存放所有 cases 命名元组对象 17 self.case_list = [] 18 # 打开 excel 文件 19 self.wb = load_workbook(self.filename) 20 # 定位表单 21 if self.sheetname is None: # 如果没有传 sheetname 这个参数,就默认获取第一个表单 22 self.ws = self.wb.active 23 else: 24 self.ws = self.wb[self.sheetname] 25 # 取 excel 表头,构造出来一个元组 26 self.sheet_head_tuple = tuple(self.ws.iter_rows(max_row=1, values_only=True))[0] 27 # 创建一个元组类 28 self.cases = namedtuple("cases", self.sheet_head_tuple, rename=True) 29 # 三元运算 30 # self.ws = self.wb[self.sheetname] if self.sheetname is not None else self.wb.active 31 32 def get_cases(self): 33 """ 34 获取所有的测试用例 35 :return: 存放 cases 命名元组的列表 36 """ 37 for row_data in self.ws.iter_rows(min_row=2, values_only=True): 38 self.case_list.append(self.cases(*row_data)) 39 return self.case_list 40 41 def get_case(self, row): 42 """ 43 获取某一条测试用例 44 :param row: 行号 45 :return: 一个 cases 命名元组对象 46 """ 47 # 判断行号是否符合条件,(数字,和 行号早最大行和最小行之间) 48 if isinstance(row, int) and (2 <= row <= self.ws.max_row): 49 return tuple(self.ws.iter_rows(min_row=row, max_row=row, values_only=True))[0] 50 # return self.case_list[row] # 这种方法不可取是因为,如果不调用 get_cases ,self.cases_list 就为空 51 else: 52 print("传入行号参数有误!") 53 54 def write_result(self, row, actual, result): 55 """ 56 将实际值与测试用例执行的结果保存到 excel 57 :param row: 行号 58 :param actual: 实际值 59 :param result: 测试结果: “Pass” or “Fail” 60 :return: 61 """ 62 if isinstance(row, int) and (2 <= row <= self.ws.max_row): 63 self.ws.cell(row=row, column=do_config(‘excel‘, ‘actual_col‘), value=actual) 64 self.ws.cell(row=row, column=do_config(‘excel‘, ‘result_col‘), value=result) 65 self.wb.save(self.filename) 66 else: 67 print("传入行号参数有误!") 68 69 70 do_excel = HandleExcel(do_config(‘file name‘, ‘cases_path‘)) 71 72 if __name__ == ‘__main__‘: 73 # file_name = "cases.xlsx" 74 # one_excel = HandleExcel(filename=file_name) 75 cases = do_excel.get_cases() 76 print(cases) 77 one_case = do_excel.get_case(2) 78 print(do_excel) 79 do_excel.write_result(2, "ces", "测试")
1 # 封装配置文件的代码 2 3 from configparser import ConfigParser 4 5 6 class HandleConfig(ConfigParser): 7 """ 8 定义处理配置文件的类 9 """ 10 11 def __init__(self): # 对父类的构造方法进行拓展 12 # 调用父类的构造方法 13 super().__init__() # 重写或者拓展父类的构造方法,往往我们需要先调用父类的构造方法 14 self.filename = ‘test_case.conf‘ 15 self.read(self.filename, encoding=‘utf-8‘) # 读取配置文件 16 # self 是 ConfigParer 的对象,因为 HandleConfig 继承了父类,所以可以直接调用 17 18 def __call__(self, section=‘DEFAULT‘, option=None, is_eval=False, is_bool=False): 19 """ 20 ’对象()‘这种形式,__call__ 方法会被调用 21 :param section: 区域名 22 :param option: 选项名 23 :param is_eval: 为默认参数,是否进行 eval 函数转换,默认不转换 24 :param is_bool: 选项所对应的值是否需要转换为 bool 类型,默认不转换 25 :return: 26 """ 27 if option is None: 28 # 1、一个对象() --> 返回 DEFAULT 默认区域下的所有选项,构造成一个字典 29 # 2、一个对象(区域名) --> 能够获取此区域下的所有选项,返回一个字典 30 return dict(self[section]) 31 32 if isinstance(is_bool, bool): 33 if is_bool: 34 # 3、一个对象(区域名, 选项名,is_bool=True) --> 将获取到的数据使用 getboolean() 方法来获取 35 return self.getboolean(section, option) 36 else: 37 raise ValueError(‘is_bool 必须是 bool 类型。‘) # 手动抛出异常 38 39 data = self.get(section, option) 40 # 4、一个对象(区域名, 选项名) --> 通过区域名以及选项名来获取值 41 42 # 5、如果获取到的数据为数字类型的字符串,自动转换为 python 中的 int 类型 43 if data.isdigit(): # 判断是否为数字类型的字符串 44 return int(data) 45 try: 46 return float(data) # 如果为浮点类型的字符串,则直接转换为 float 类型 47 except ValueError: 48 pass 49 50 if isinstance(is_eval, bool): 51 if is_eval: 52 # 6、一个对象(is_eval=True) --> 将获取到的数据使用 eval 函数进行转换 53 return eval(data) 54 else: 55 raise ValueError(‘is_eval 必须是 bool 类型。‘) 56 57 return data 58 59 60 do_config = HandleConfig() 61 62 63 if __name__ == ‘__main__‘: 64 config = HandleConfig() 65 print(config()) 66 print(config(‘excel‘)) 67 a = config(‘excel‘, ‘two_res‘) # print(config(‘excel‘, ‘actual_col‘)) 68 print(f‘值为:{a} 类型为:{type(a)}‘) 69 b = config(‘excel‘, ‘two_res‘, is_bool=True) # print(config(‘excel‘, ‘two_res‘, is_bool=True)) 70 print(f‘值为:{b} 类型为:{type(b)}‘) 71 c = config(‘excel‘, ‘five_res‘, is_eval=True) 72 print(f‘值为:{c} 类型为:{type(c)}‘) # print(config(‘excel‘, ‘five_res‘, is_eval=True))
1 import unittest 2 import inspect 3 4 from ddt import ddt, data 5 from class_06_1209_unittest_02.math_operation import MathOperation 6 from openpyxl import load_workbook 7 from collections import namedtuple 8 9 from class_13_0111_rewrite_unittest.excel_handle import do_excel 10 from class_13_0111_rewrite_unittest.config_handle import do_config 11 from class_13_0111_rewrite_unittest.log_handle import do_log 12 13 14 @ddt 15 class TestMulti(unittest.TestCase): 16 """ 17 测试两数相乘 18 """ 19 # handle_config = HandleConfig() 20 # handle_excel = HandleExcel(do_config(‘file name‘, ‘cases_path‘)) 21 cases = do_excel.get_cases() # 获取所有的用例,返回一个嵌套命名元组的列表 22 23 @classmethod 24 def setUpClass(cls) -> None: 25 """ 26 重写父类的类方法 27 所有用例执行之前,会被调用一次 --> 整个测试类调用之前,执行一次 28 :return: 29 """ 30 do_log.info("{:=^40s} ".format("开始执行用例!")) 31 32 @classmethod 33 def tearDownClass(cls) -> None: 34 """ 35 重写父类的类方法 36 所有用例执行之后,会被调用一次 --> 整个测试类调用之后,执行一次 37 :return: 38 """ 39 do_log.info("{:=^40s} ".format("用例执行结束!")) 40 41 @data(*cases) 42 def test_multi(self, data_namedtuple): 43 """ 44 两数相乘 45 :return: 46 """ 47 # 能够通过 inspect.stack 方法查看当前运行的实例名称 48 do_log.info(f"Running Test Method: {inspect.stack()[0][3]} ") 49 50 case_id = data_namedtuple.case_id 51 msg = data_namedtuple.title 52 l_date = data_namedtuple.l_date 53 r_date = data_namedtuple.r_date 54 expected = data_namedtuple.expected 55 56 # 获取实际结果 57 real_result = MathOperation(l_date, r_date).mul() 58 # 预期结果 59 expect_result = expected 60 # msg 61 run_success_msg = do_config(‘msg‘, ‘success_result‘) 62 run_fail_msg = do_config(‘msg‘, ‘fail_result‘) 63 # 断言 64 try: 65 self.assertEqual(expect_result, real_result, msg="{}失败!".format(msg)) 66 except AssertionError as e: 67 # 记录日志 68 do_log.error("{},执行结果为:{} 具体异常为:{} ".format(msg, run_fail_msg, e)) # 将执行失败的信息写入到文件 69 do_excel.write_result(row=case_id+1, actual=real_result, result=run_fail_msg) 70 raise e 71 else: 72 # self.file.write("{},执行结果为:{} ".format(msg, run_success_msg)) # 将执行成功的信息写入到文件 73 do_log.info("{},执行结果为:{} ".format(msg, run_success_msg)) 74 do_excel.write_result(row=case_id+1, actual=real_result, result=run_success_msg) 75 76 77 if __name__ == ‘__main__‘: 78 unittest.main()
1 # 注释不要和区域名和选项名写在一行 2 3 # 文件路径配置 4 [file name] 5 # cases_path 为测试用例 excel 文件的路径 6 # log_path 为记录日志的文件路径 7 cases_path = cases.xlsx 8 log_path = run_result_1.txt 9 report_html_name = test_result 10 11 # 提示信息 12 [msg] 13 ; success_result 为用例执行成功的提示信息 14 ; fail_path 为用例执行失败的提示信息 15 success_result = Pass 16 fail_result = Fail 17 18 # excel 相关配置 19 [excel] 20 # actual_col 为将用例执行的实际结果存储到 excel 中的列号 21 # result_col 为将用例执行的结果存储到 excel 中的列号 22 actual_col = 6 23 result_col = 7 24 25 # 日志相关配置 26 [log] 27 # 日志器名称 28 logger_name = case 29 # 日志器日志等级 30 logger_level = DEBUG 31 # 日志文件名 32 log_filename = case.log 33 # 一个日志文件的最大字节数 34 maxBytes = 4096 35 # 备份文件数 36 backupCount = 3 37 # 输出到控制台的日志等级 38 console_level = ERROR 39 # 输出到文件的日志等级 40 file_level = INFO 41 # 控制台使用的日志简单格式 42 # 配置文件出现 % ,需要使用 % 来转义 43 simple_formatter = %%(asctime)s - [%%(levelname)s] - [日志信息]:%%(message)s 44 # 日志文件使用日志复杂格式 45 verbose_formatter = %%(asctime)s - [%%(levelname)s] - %%(module)s - %%(name)s - %%(lineno)d - [日志信息]:%%(message)s
以上是关于自动化测试框架的主要内容,如果未能解决你的问题,请参考以下文章