自动化测试框架

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", "测试")
excel处理 类的封装
技术图片
 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
配置文件

以上是关于自动化测试框架的主要内容,如果未能解决你的问题,请参考以下文章

text BATS测试框架片段

接口自动化简单框架

前端测试框架Jest总结

接口自动化测试PHPUnit-框架代码开发1

自动化测试模型

pytest接口自动化测试框架 | 用python代码测试接口