日志相关、全量字段校验
一、日志简介
日志也叫 log,通常对应的 xxx.log 的日志文件。文件的作用是记录系统运行过程中,产生的信息。
搜集日志的作用:
查看系统运行是否正常。
分析、定位 bug
二、日志级别
logging.DEBUG:调试级别【高】,打印非常详细的日志信息。适用于代码调试。
logging.INFO:信息级别【次高】,一般用于记录突出强调的运行过程步骤。
logging.WARNING:警告级别【中】,可能出现潜在错误的情况,一般不影响系统使用。
logging.ERROR:错误级别【低】,打印错误异常信息,出现Bug。
logging.CRITICAL:严重错误级别【极低】,系统可能无法运行。
特性:
日志级别设定后,只有比该级别低的日志会写入日志。
三、日志代码分析
1、日志步骤:
# 0. 导包 # 1. 创建日志器对象 # 2. 设置日志打印级别 # logging.DEBUG 调试级别 # logging.INFO 信息级别 # logging.WARNING 警告级别 # logging.ERROR 错误级别 # logging.CRITICAL 严重错误级别 # 3. 创建处理器对象 # 创建 输出到控制台 处理器对象 # 创建 输出到日志文件 处理器对象 # 4. 创建日志信息格式 # 5. 将日志信息格式设置给处理器 #设置给 控制台处理器 # 设置给 日志文件处理器 # 6. 给日志器添加处理器 # 给日志对象 添加 控制台处理器 # 给日志对象 添加 日志文件处理器 # 7. 打印日志 """
2、日志代码:
import logging.handlers import logging import time # 1. 创建日志器对象 logger = logging.getLogger() # 2. 设置日志打印级别 logger.setLevel(logging.DEBUG) #logging.DEBUG #调试级别 # logging.INFO 信息级别 # logging.WARNING 警告级别 # logging.ERROR 错误级别 # logging.CRITICAL 严重错误级别 # 3.1 创建 输出到控制台 处理器对象 st = logging.StreamHandler() # 3.2 创建 输出到日志文件 处理器对象 fh = logging.handlers.TimedRotatingFileHandler('a.log', when='midnight', interval=1, backupCount=3, encoding='utf-8')
#'a.log':表示生成日志文件的名字 # when 字符串,指定日志切分间隔时间的单位。midnight:凌晨:12点。 # interval 是间隔时间单位的个数,指等待多少个 when 后继续进行日志记录,1代表一天一个,3代表一天三个 # backupCount 是保留日志文件的个数 # 4. 创建日志信息格式 fmt = "%(asctime)s %(levelname)s [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s" formatter = logging.Formatter(fmt)
#%(asctime)s:时间
#%(levelname)s:打印该条信息的级别
#%(message)s:输出信息
# 5.1 日志信息格式 设置给 控制台处理器 st.setFormatter(formatter) # 5.2 日志信息格式 设置给 日志文件处理器 fh.setFormatter(formatter) # 6.1 给日志器对象 添加 控制台处理器 logger.addHandler(st) # 6.2 给日志器对象 添加 日志文件处理器 logger.addHandler(fh) #7. 打印日志 while True: # logging.debug('我是一个调试级别的日志') # logging.info('我是一个信息级别的日志') logging.warning('test log sh-26') # logging.error('我是一个错误级别的日志') # logging.critical('我是一个严重错误级别的日志')
time.sleep(1)
四、日志的使用(将上面的日志代码封装到函数方法 def init_log_config()里面)记住在项目中去掉 第七步。
1、可修改位置
2、使用步骤
1. 调用 init_log_confifig() 函数,初始化日志信息。
2. 指定 日志级别,打印 日志信息。
3、代码实例
import logging import logging.handlers def init_log_config(fileName, when = "midnight",interval=1, backupCount=3,): #将参数设置为缺省参数,可以自己传参修改 # 1. 创建日志器对象 logger = logging.getLogger() # 2. 设置日志打印级别 logger.setLevel(logging.DEBUG) # 3.1 创建 输出到控制台 处理器对象,控制台不需要向日志文件一样 st = logging.StreamHandler() # 3.2 创建 输出到日志文件 处理器对象 fh = logging.handlers.TimedRotatingFileHandler(filename=fileName, when=when, interval=interval, backupCount=backupCount, encoding='utf-8') # 4. 创建日志信息格式 fmt = "%(asctime)s %(levelname)s [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s" formatter = logging.Formatter(fmt) # 5.1 日志信息格式 设置给 控制台处理器 st.setFormatter(formatter) # 5.2 日志信息格式 设置给 日志文件处理器 fh.setFormatter(formatter) # 6.1 给日志器对象 添加 控制台处理器 logger.addHandler(st) # 6.2 给日志器对象 添加 日志文件处理器 logger.addHandler(fh) if __name__ == "__main__": init_log_config("aaa.log") a = 10000 logging.info(f"日志信息为:a={a}")
4、项目使用
import logging import unittest # 导入添加员工接口 from api.ihrm_emp_curd import IhrmEmpCURD # 导入断言方法 from common.assert_util import assert_util # 导入数据库操作工具,解决手机号唯一问题 from common.db_util import DBUtil # 导入全局手机号 from config import TEL #导包解决参数化 from common.read_json_util import read_json_data from parameterized import parameterized #导入打印日志包 from logging_use import init_log_config class TestEmpAdd(unittest.TestCase): #添加打印日志 init_log_config("testempadd.log") # 解决手机号唯一问题 def setUp(self) -> None: # 删除手机号 delete_sql = f"delete from bs_user where mobile = '{TEL}'" # 此时可以格式化 DBUtil.uid_db(delete_sql) def tearDown(self) -> None: # 删除手机号 delete_sql = f"delete from bs_user where mobile = '{TEL}'" # 此时可以格式化 DBUtil.uid_db(delete_sql) #通用测试方法添加员工 @parameterized.expand(read_json_data()) def test01_add(self,desc,json_data,status_code,success,code,message): # 准备数据 header = { "Content-Type": "application/json", "Authorization": "Bearer b040daed-39c1-4302-8777-f950770c8a26" } # 调用自己封装的接口 resp = IhrmEmpCURD.add_emp(header=header, json_data=json_data) #打印日志 logging.info(f"res = {resp}") # 断言 assert_util(self, resp, status_code, success, code, message)
五、全量字段校验
校验接⼝返回响应结果的全部字段(更进一步的断言)
校验内容:
字段值
字段名 或 字段类型
校验流程:
定义json语法校验格式
⽐对接口实际响应数据是否符合json校验格式
安装jsonschema:
pip install jsonschema
1、校验方式
1、在线工具校验
http://json-schema-validator.herokuapp.com
https://www.jsonschemavalidator.net 【推荐】
2、Python代码校验
步骤:
1 导包 import jsonschema
2 定义 jsonschema格式 数据校验规则
3 调⽤ jsonschema.validate(instance="json数据", schema="jsonshema规则")
查验校验结果:
校验通过:返回 None校验失败
schema 规则错误,返回 SchemaError
json 数据错误,返回 ValidationError
案例
# 1. 导包 import jsonschema # 2. 创建 校验规则 schema = { "type": "object", "properties": { "success": { "type": "boolean" }, "code": { "type": "integer" }, "message": { "type": "string" } }, "required": ["success", "code", "message"] } # 准备待校验数据 data = { "success": True, "code": 10000, "message": "操作成功" } # 3. 调用 validate 方法,实现校验 result = jsonschema.validate(instance=data, schema=schema) print("result =", result) # None: 代表校验通过 # ValidationError:数据 与 校验规则不符 # SchemaError: 校验规则 语法有误
2、json schema 语法
type 关键字:约束数据类型
例子
properties关键字:是 type关键字的辅助。用于 type 的值为 object 的场景。指定 对象中 每个字段的校验规则。 可以嵌套使用
例子:
import jsonschema # 准备校验规则 schema = { "type": "object", "properties": { "success": {"type": "boolean"}, "code": {"type:": "integer"}, "message": {"type": "string"}, "money": {"type": "number"}, "address": {"type": "null"}, "data": { "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"}, "height": {"type": "number"} } }, "luckyNumber": {"type": "array"} } } # 准备测试数据 data = { "success": True, "code": 10000, "message": "操作成功", "money": 6.66, "address": None, "data": { "name": "tom", "age": 18, "height": 1.78 }, "luckyNumber": [6, 8, 9] } # 调用方法进行校验 res = jsonschema.validate(instance=data, schema=schema) print(res)
required关键字
作用:校验对象中必须存在的字段。字段名必须是字符串,且唯⼀
import jsonschema # 测试数据 data = { "success": True, "code": 10000, "message": "操作成功", "data": None, } # 校验规则 schema = { "type": "object", "required": ["success", "code", "message", "data"] } # 调用方法校验 res = jsonschema.validate(instance=data, schema=schema) print(res)
const关键字
作用:校验字段值是⼀个固定值。
import jsonschema # 测试数据 data = { "success": True, "code": 10000, "message": "操作成功", "data": None, } # 校验规则 schema = { "type": "object", "properties": { "success": {"const": True}, "code": {"const": 10000}, "message": {"const": "操作成功"}, "data": {"const": None} }, "required": ["success", "code", "message", "data"] } # 调用方法校验 res = jsonschema.validate(instance=data, schema=schema) print(res)
pattern关键字
作用:指定正则表达式,对字符串进行模糊匹配
import jsonschema # 测试数据 data = { "message": "!jeklff37294操作成功43289hke", "mobile": "15900000002" } # 校验规则 schema = { "type": "object", "properties": { "message": {"pattern": "操作成功"}, "mobile": {"pattern": "^[0-9]{11}$"} } } # 调用方法校验 res = jsonschema.validate(instance=data, schema=schema) print(res)
综合案例:
""" 综合案例 """ # 测试数据 import jsonschema data = { "success": False, "code": 10000, "message": "xxx登录成功", "data": { "age": 20, "name": "lily" } } # 校验规则 schema = { "type": "object", "properties": { "success": {"type": "boolean"}, "code": {"type": "integer"}, "message": {"pattern": "登录成功$"}, "data": { "type": "object", "properties": { "name": {"const": "lily"}, "age": {"const": 20} }, "required": ["name", "age"] } }, "required": ["success", "code", "message", "data"] } # 调用测试方法 res = jsonschema.validate(instance=data, schema=schema) print(res)
项目里使用全量字段校验(即用 全量字段替换掉普通断言)即可
项目里使用日志(直接在 run_suite.py 里面使用日志。在此处需要初始化全局的日志。然后其他函数内,所有 print 的地方都可以用日志替换)(将日志 init_log_config.py 放到 common下)
""" 1、创建测试类套件实例 2、添加测试类 3、创建Htmlreport 类实例runner 4、runner调用run ,传入suite """ import logging import unittest from config import BASE_DIR from scripts.test_emp_add import TestEmpAdd from scripts.test_ihrm_login import TestIhrmLogin from htmltestreport import HTMLTestReport #导入日志函数 from logging_use import init_log_config #初始化日志配置 init_log_config(BASE_DIR + "/log/ihrm.log") ################### 初始化日志 #实例化 suite = unittest.TestSuite() logging.info("测试套件实例,创建成功!") #使用日志 #条件测试类 suite.addTest(unittest.makeSuite(TestEmpAdd)) suite.addTest(unittest.makeSuite(TestIhrmLogin)) #创建HTMLReport runner = HTMLTestReport("./report/ihrm.html",description="ihrm测试报告",title="itrm_测试报告") #相对路径 #runner = HTMLTestReport(BASE_DIR + "/report/ihrm.html") #绝对路径 # runner.run(suite) logging.info("测试报告生成成功")