首页 > 编程语言 >python unittest 接口自动化遇到的问题记录

python unittest 接口自动化遇到的问题记录

时间:2023-03-11 11:33:22浏览次数:39  
标签:__ LOG get python unittest 接口 logger config self

1. ConfigParser类读取config.ini的options全部返回为小写字母

查看configparser.ConfigParser类中,是因为optionxform方法返回了optionstr.lower()

 def optionxform(self, optionstr):
        return optionstr.lower()

第一种方法是直接修改源码,把return optionstr.lower() 改成return optionstr.
此种解决方案的不足之处是只能在本机生效,换台机器就会出问题

第二种方法是自己封装一个MyConfig类,继承ConfigParser,重写optionxform方法
(方案参考https://blog.csdn.net/Ha_hha/article/details/78965011)

from configparser import ConfigParser
import os


conf = os.path.join(os.path.dirname(__file__), "../config/config.ini")


class MyConfig(ConfigParser):
    # 继承ConfigParser,解决读取options自动转换成小写的问题
    def __init__(self):
        super().__init__()

    def optionxform(self, optionstr):
        # 重写optionxform方法,解决ConfigParser类读取的options都会转换成小写的问题
        return optionstr


config = MyConfig()
# logger.debug("以utf-8编码方式打开配置文件{}".format(conf))
config.read(filenames=conf, encoding="utf-8")


if __name__ == "__main__":
    print(config.sections())
    print(config.options("LOG"))

2. 日志打印多次

自己封装的日志模块,在多个地方都有调用,用于输出日志,运行runner时发现日志有4条重复记录,百度后发现是因为在多个模块中实例化自定义的log类,每次实例化就会addhandler一次,有4处实例化就会addhandler4次,导致日志输出4次

# filename: log.py
import logging


class MyLogger:
    def __new__(self):
        # 1. 创建log收集器,设置日志收集级别
        mylogger = logging.getLogger("mylogger")
        mylogger.setLevel(config.get("LOG", "LOG_LEVEL"))

        # 2. 创建输出渠道,设置日志输出级别
        sh = logging.StreamHandler()
        fh = logging.FileHandler(config.get("LOG", "FILENAME"), mode="w", encoding="utf-8")
        sh.setLevel(config.get("LOG", "SH_LEVEL"))
        fh.setLevel(config.get("LOG", "FH_LEVEL"))

        # 3. 设置文件输出格式,添加格式
        fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT", raw=True))   # 读取包含%符号时,避免被转义,增加一个参数raw=True
        fh.setFormatter(fmt)

        # 4. 把输出渠道添加到日志收集器
        mylogger.addHandler(sh)
        mylogger.addHandler(fh)
        return mylogger

其他调用log模块的模块有4个,其中1个代码如下:

# filename: operate_excel.py 
import openpyxl
import os
from prac_unittest_3.common.log import MyLogger   # 导入MyLogger类

logger = MyLogger()  # 每个调用log模块的地方都要实例化一个logger对象

class CaseObj:
    def __init__(self, zip_obj):
        for i in list(zip_obj):
            setattr(self, i[0], i[1])


# 1. 封装一个读取excel的类
class ReadExcel:
    def __init__(self, filename, sheetname):
        self.filename = filename
        self.sheetname = sheetname
        self.wb = openpyxl.load_workbook(self.filename)
        self.sh = self.wb[self.sheetname]
        logger.debug("打开文件{}的{}表单".format(self.filename, self.sheetname))

    def read_data_obj(self):
        cases = []
        # self.sh.rows 是一个生成器,不能通过下标来访问,有2种方案获得表头,一种是self.sh.rows转换成list先,再通过list下标去访问.第二种是通过next()来调用,第一次用next()来调用,第2行及以后的,直接遍历,遍历会自动调用next() 方法
        firstrow = next(self.sh.rows)
        # 1. 读取第一行作为表头,存放在title列表
        titles = [cell.value for cell in firstrow]
        logger.debug("读取第一行:{}".format(titles))

        # 2. 读取第2--max_row,存放在data列表
        for row in self.sh.rows:
            datas = [cell.value for cell in row]
            logger.debug("读取到的数据为:{}".format(datas))
            # 3. 聚合title和data,形成字典形式
            case_obj = CaseObj(zip(titles, datas))
            logger.debug("组装成用例:{}".format(case_obj))
            # 4. 每条用例追加到总的用例列表中
            cases.append(case_obj)
        return cases

    def write_data(self, row, column, data):
        logger.debug("第{}行第{}列写入的内容为:{}".format(row, column, data))
        self.sh.cell(row=row, column=column).value = data
        logger.debug("保存内容到文件{}".format(self.filename))
        self.wb.save(self.filename)

修改log模块,先实例化一个logger对象,其他需要用到日志模块的,直接导入这个logger对象即可

# filename: log.py
import logging


class MyLogger:
    def __new__(self):
        # 1. 创建log收集器,设置日志收集级别
        mylogger = logging.getLogger("mylogger")
        mylogger.setLevel(config.get("LOG", "LOG_LEVEL"))

        # 2. 创建输出渠道,设置日志输出级别
        sh = logging.StreamHandler()
        fh = logging.FileHandler(config.get("LOG", "FILENAME"), mode="w", encoding="utf-8")
        sh.setLevel(config.get("LOG", "SH_LEVEL"))
        fh.setLevel(config.get("LOG", "FH_LEVEL"))

        # 3. 设置文件输出格式,添加格式
        fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT", raw=True))   # 读取包含%符号时,避免被转义,增加一个参数raw=True
        fh.setFormatter(fmt)

        # 4. 把输出渠道添加到日志收集器
        mylogger.addHandler(sh)
        mylogger.addHandler(fh)
        return mylogger

logger = MyLogger()   # 在log模块中实例化MyLogger类,其他需要用到log模块的地方直接import这个logger对象即可。实现只需实例化一次即可到处调用

operate_excel.py 只需修改2行代码,import MyLogger改为import logger,把实例化MyLogger类去掉

# filename: operate_excel.py 
import openpyxl
import os
from prac_unittest_3.common.log import logger   # 修改为直接导入log模块的logger对象,直接调用logger.debug() 就可以输出日志


class CaseObj:
    def __init__(self, zip_obj):
        for i in list(zip_obj):
            setattr(self, i[0], i[1])


# 1. 封装一个读取excel的类
class ReadExcel:
    def __init__(self, filename, sheetname):
        self.filename = filename
        self.sheetname = sheetname
        self.wb = openpyxl.load_workbook(self.filename)
        self.sh = self.wb[self.sheetname]
        logger.debug("打开文件{}的{}表单".format(self.filename, self.sheetname))

    def read_data_obj(self):
        cases = []
        # self.sh.rows 是一个生成器,不能通过下标来访问,有2种方案获得表头,一种是self.sh.rows转换成list先,再通过list下标去访问.第二种是通过next()来调用,第一次用next()来调用,第2行及以后的,直接遍历,遍历会自动调用next() 方法
        firstrow = next(self.sh.rows)
        # 1. 读取第一行作为表头,存放在title列表
        titles = [cell.value for cell in firstrow]
        logger.debug("读取第一行:{}".format(titles))

        # 2. 读取第2--max_row,存放在data列表
        for row in self.sh.rows:
            datas = [cell.value for cell in row]
            logger.debug("读取到的数据为:{}".format(datas))
            # 3. 聚合title和data,形成字典形式
            case_obj = CaseObj(zip(titles, datas))
            logger.debug("组装成用例:{}".format(case_obj))
            # 4. 每条用例追加到总的用例列表中
            cases.append(case_obj)
        return cases

    def write_data(self, row, column, data):
        logger.debug("第{}行第{}列写入的内容为:{}".format(row, column, data))
        self.sh.cell(row=row, column=column).value = data
        logger.debug("保存内容到文件{}".format(self.filename))
        self.wb.save(self.filename)

2.封装log模块,从配置文件中读取日志格式参数报错

LOG_FORMAT= "%(asctime)s %(filename)s line:%(lineno)d %(levelname)s: %(message)s",由于含有百分号%导致无法读取
configparser.InterpolationMissingOptionError: Bad value substitution: option 'LOG_FORMAT' in section 'LOG' contains an interpolation key 'asctime' which is not a valid option name. Raw value: '"%(asctime)s %(filename)s line:%(lineno)d %(levelname)s: %(message)s"'

C:\Users\MACHENIKE\AppData\Local\Programs\Python\Python37\python.exe "D:/Documentss/WeChat Files/wxid_t7usl9w03ogs22/FileStorage/File/2023-02/训练营资料(1)/day01/prac_unittest_3/common/log.py"
Traceback (most recent call last):
 File "D:/Documentss/WeChat Files/wxid_t7usl9w03ogs22/FileStorage/File/2023-02/训练营资料(1)/day01/prac_unittest_3/common/log.py", line 34, in <module>
   logger = MyLogger()
 File "D:/Documentss/WeChat Files/wxid_t7usl9w03ogs22/FileStorage/File/2023-02/训练营资料(1)/day01/prac_unittest_3/common/log.py", line 25, in __new__
   fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT"))   # 读取包含%符号时,避免被转义,增加一个参数raw=True
 File "C:\Users\MACHENIKE\AppData\Local\Programs\Python\Python37\lib\configparser.py", line 799, in get
   d)
 File "C:\Users\MACHENIKE\AppData\Local\Programs\Python\Python37\lib\configparser.py", line 394, in before_get
   self._interpolate_some(parser, option, L, value, section, defaults, 1)
 File "C:\Users\MACHENIKE\AppData\Local\Programs\Python\Python37\lib\configparser.py", line 434, in _interpolate_some
   option, section, rawval, var) from None
configparser.InterpolationMissingOptionError: Bad value substitution: option 'LOG_FORMAT' in section 'LOG' contains an interpolation key 'asctime' which is not a valid option name. Raw value: '"%(asctime)s  %(filename)s line:%(lineno)d %(levelname)s: %(message)s"'

Process finished with exit code 1

代码:

import logging
from prac_unittest_3.common.config import config


class MyLogger:
    def __new__(self):
        # 1. 创建log收集器,设置日志收集级别
        mylogger = logging.getLogger("mylogger")
        mylogger.setLevel(config.get("LOG", "LOG_LEVEL"))

        # 2. 创建输出渠道,设置日志输出级别
        sh = logging.StreamHandler()
        fh = logging.FileHandler(config.get("LOG", "FILENAME"), mode="w", encoding="utf-8")
        sh.setLevel(config.get("LOG", "SH_LEVEL"))
        fh.setLevel(config.get("LOG", "FH_LEVEL"))

        # 3. 设置文件输出格式,添加格式
        fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT")) 
        fh.setFormatter(fmt)

        # 4. 把输出渠道添加到日志收集器
        mylogger.addHandler(sh)
        mylogger.addHandler(fh)
        return mylogger


logger = MyLogger()


if __name__ == "__main__":
    logger.debug("------------debug")
    logger.error("------------error")

只需在读取config.get("LOG","LOG_FORMAT",raw=True)变量时,增加一个raw=True属性即可,修改为

import logging
from prac_unittest_3.common.config import config


class MyLogger:
    def __new__(self):
        # 1. 创建log收集器,设置日志收集级别
        mylogger = logging.getLogger("mylogger")
        mylogger.setLevel(config.get("LOG", "LOG_LEVEL"))

        # 2. 创建输出渠道,设置日志输出级别
        sh = logging.StreamHandler()
        fh = logging.FileHandler(config.get("LOG", "FILENAME"), mode="w", encoding="utf-8")
        sh.setLevel(config.get("LOG", "SH_LEVEL"))
        fh.setLevel(config.get("LOG", "FH_LEVEL"))

        # 3. 设置文件输出格式,添加格式
        fmt = logging.Formatter(config.get("LOG", "LOG_FORMAT", raw=True))   # 读取包含%符号时,避免被转义,增加一个参数raw=True
        fh.setFormatter(fmt)

        # 4. 把输出渠道添加到日志收集器
        mylogger.addHandler(sh)
        mylogger.addHandler(fh)
        return mylogger


logger = MyLogger()

if __name__ == "__main__":
    logger.debug("------------debug")
    logger.error("------------error")

标签:__,LOG,get,python,unittest,接口,logger,config,self
From: https://www.cnblogs.com/xiaozhuangAna/p/17205553.html

相关文章

  • Python 3 os.walk读取指定文件路径后,打印路径参数为空
    今天有时间自己尝试了一下os.walk的小实验,结果出现了一个小问题:在交互模式下,运行我的python脚本,没有打印任何内容  返回去看一下test.py内容 返回去看一下文件路......
  • 最全的Python虚拟环境使用方法
    一、使用virtualenv1.使用pippipinstallvirtualenv2.创建运行环境virtualenv[虚拟环境名称]virtualenvvenv#如果不想使用系统的包,加上–no-site-packeag......
  • 跟艾文学编程《零基础入门学Python》PyCharm 安装
    作者:艾文,计算机硕士学位,企业内训讲师和金牌面试官,公司资深算法专家,现就职BAT一线大厂。学习目标PyCharm下载PyCharm工具的使用利用PyCharm工具开发第一个应用程序PyChar......
  • 实验1 Python开发环境使用和编程初体验
    实验任务1 task1_1print('hey','u')x,y,z=1,2,3print(x,y,z)print('x=%d,y=%d,z=%d'%(x,y,z))print('x={},y={},z={}'.format(x,y,z))print('x=%d,y......
  • 什么叫有限状态机?Python中如何实现?
    Automat是一个Python类库,用于创建有限状态机(FSM)。有限状态机是一种计算模型,它在任何时刻只处于有限数量的状态之一。有限状态机由一个状态集合、一个初始状态、一组可能的输......
  • python跳出多层for循环
    在业务逻辑中有时候会遇到两层for循环的情况,触发某些条件时,需要直接退出两层for循环而python官方是没有goto语句的那么我们可以这样实现第一种定义变量flag,根据flag......
  • python: 复制英文论文时,删除掉多余的回车
     自己平时读论文时,遇到看不懂的英文长难句时会用到翻译网站,这个时候复制pdf格式的论文时总是会出现一大堆换行符,影响翻译软件的翻译结果,所以写了个python程序自动读取剪......
  • Linux下使用python操作文件夹的一个坑
    我们通常在Windows系统中调用python内置函数os.listdir()读取文件内容,生成的文件名列表是有序的.#假若在当前目录下有一个名叫files的文件夹,其中放置0001.txt,0002.txt,......
  • Python猜数字游戏(4版)
    前言这是我的一次python实验,记录一下正文1.基础版在程序中预设一个0-9之间的整数,让用户通过键盘输入所猜的数,如果大于预设的数,显示“你猜的数字大于正确答案”;小于预设的数,......
  • python将图片和音频合成视频
    #encoding=utf8#-*-coding:utf-8-*-'''python合成视频'''importos#python标准库,不需要安装,用于系统文件操作相关importcv2#python非标准库,pipinstall......