python:接口自动化测试框架读取配置优化

在这里插入图片描述
前一阶段整理了自己理解的接口自动化项目框架的优化版本,这次把遗漏的环境切换和配置文件读取部分给完善了,如有小过半需要代码的,两篇文章直接复制代码即可。话不多说,进入代码的世界…

配置文件的读取

项目目录中有一个settings.py文件,这里是专门放一些配置数据的,读取到后再进行处理获取需要的值

先看setting.py文件的内容:

from pathlib import Path, PurePath

# 获取项目根目录
BASE_DIR = PurePath(Path(__file__).parent)

# 用于判断是否往企业微信发送测试报告:True是发送、False是不发送
IS_SEND = True

# 设置运行的环境变量
ENVIRONMENT = "PRO"  # 环境变量值分别为  测试:TEST;预发布:PRE;生产:PRO

# 接口请求域名
HOST = "http://apis.juhe.cn"
# 设置头信息指定域名和Content-Type类型
HEADERS = {
    
    'Content-Type': 'application/json'}

# 环境IP配置
BASE_HOST = {
    
    
    "test": None,
    "pre": None,
    "pro": None,
}

# 数据库配置
DATABASES = {
    
    
    "pro": {
    
    "host": "8.136.250.157", "port": 1234, "user": "root", "passwd": "test.2016", "db": "testing"},
}

# yaml文件路径
YAML_FILE_PATH = {
    
    
    "api_idiom": BASE_DIR.joinpath("testDatas", "idiom_modules.yml"),
    "api_match": BASE_DIR.joinpath("testDatas", "match_modules.yml"),
}

# 日志存放目录
LOGGING_PATH = BASE_DIR.joinpath("logs", f"logfile.text")

# 日志记录配置
LOGGING_CONFIG = {
    
    
    "version": 1,
    "root": {
    
    
        "level": "DEBUG",
        "handlers": ["file", "console"]
    },
    "handlers": {
    
    
        "console": {
    
    
            "class": "logging.StreamHandler",
            "level": "ERROR",
            "formatter": "console_formatters"
        },
        "file": {
    
    
            "class": "logging.handlers.RotatingFileHandler",
            "formatter": "file_formatters",
            "filename": LOGGING_PATH,
            "level": "DEBUG",
            "maxBytes": 100,
            "backupCount": 5,
            "encoding": "utf-8"
        }
    },
    "formatters": {
    
    
        "console_formatters": {
    
    
            "format": "%(asctime)s [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s",
            "datefmt": "%Y%m%d %H:%M:%S"
        },
        "file_formatters": {
    
    
            'format': "%(asctime)s [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s- %(pathname)s",
            "datefmt": "%Y%m%d %H:%M:%S"
        }
    }
}

名词解释:

  • BASE_DIR是项目的根路径

  • IS_SEND是判断邮件的发送

  • ENVIRONMENT是切换环境

  • HOST是请求的域名

  • HEADERS是默认请求头

  • BASE_HOST是环境IP

  • DATABASES是数据库配置

  • YAML_FILE_PATH是读取yaml文件的路径

  • LOGGING_PATH是日志文件的路径

  • LOGGING_CONFIG日志的配置

是如何读取settings.py中的配置的呢,这也是借鉴了django框架的懒加载,当然我这是简化版的懒加载(可能还没达到懒加载,哈哈…)。这段代码是放置在apiTest/common/init.py中的:

# apiTest/common/__init__.py

import importlib

__all__ = ["setting"]


class LazySetting:

    def __init__(self, settings_module):

        _mod = importlib.import_module(settings_module)

        self._explicit_settings = set()
        for setting in dir(_mod):
            if setting.isupper():
                setting_value = getattr(_mod, setting)
                if isinstance(setting, (list, tuple)):
                    raise TypeError("类型不符合要求!")
                setattr(self, setting, setting_value)
                self._explicit_settings.add(setting)

    def _is_overridden(self, setting):
        return setting in self._explicit_settings

    def get_setting(self, name):
        for i in self._explicit_settings:
            if self._is_overridden(i) and (name == i):
                return getattr(self, i)


setting = LazySetting("settings")

这段代码,大家可自行理解,我怕解释不清楚,让大家搞混掉了,其实实际操作一下就能看懂个大概了。

settings.py文件中的数据就被拿到了,然后再去进行处理,处理成自己需要的那种:

# apiTest/common/readEnvironment.py

import os
import common

_DATA = common.setting.get_setting

__all__ = ["MappingRelation"]


class Config:
    def __getitem__(self, key):
        """
        魔术方法,把类变成字典取值
        :param key:
        :return:
        """
        return self.__getattribute__(key)


class Test_DATA(Config):
    """
    测试环境配置信息
    """

    HOST = _DATA("HOST")
    HEADERS = _DATA("HEADERS")
    YAML_PATH = _DATA("YAML_FILE_PATH")
    LMS_LOGGING = _DATA("LOGGING_CONFIG")
    BASE_URL = _DATA("BASE_HOST")["test"]
    _DATABASE = _DATA("_DATABASES")["pro"]


class Pre_DATA(Config):
    """
    预发布环境配置信息
    """

    HOST = _DATA("HOST")
    HEADERS = _DATA("HEADERS")
    YAML_PATH = _DATA("YAML_FILE_PATH")
    LMS_LOGGING = _DATA("LOGGING_CONFIG")
    BASE_URL = _DATA("BASE_HOST")["pre"]
    _DATABASE = _DATA("_DATABASES")["pro"]


class Pro_DATA(Config):
    """
    线上环境配置信息
    """

    HOST = _DATA("HOST")
    HEADERS = _DATA("HEADERS")
    YAML_PATH = _DATA("YAML_FILE_PATH")
    LMS_LOGGING = _DATA("LOGGING_CONFIG")
    BASE_URL = _DATA("BASE_HOST")["pro"]
    _DATABASE = _DATA("_DATABASES")["pro"]


class MappingRelation:
    # 设置映射关系
    _mapping = {
    
    
        'PRO': Pro_DATA,
        'PRE': Pre_DATA,
        'TEST': Test_DATA
    }

    @property
    def map(self):
        # 返回映射关系
        env = os.environ.get('ENV', _DATA("ENVIRONMENT")).upper()  # 配置文件中读取环境变量
        return self._mapping[env]()  # 获取指定的环境

名词解释:

  • _DATA是common.setting.get_setting方法赋值的变量

  • Config类是写了两个魔术方法,getitem是可变成下标取值的样式,而getattribute是属性拦截器

  • Test_DATA子类继承了Congif类,配置的是测试环境

  • Pre_DATA子类继承了Congif类,配置的是预发环境

  • Pro_DATA子类继承了Congif类,配置的是生产环境

  • MappingRelation类是映射上述三个子类,读取配置文件中的环境变量,去返回对应的环境数据

这里处理完成后,再去编写一个.py文件,专门调用MappingRelation类来获取对应的数据:

# apiTest/common/mapMnvironment.py

from urllib import parse
from common.readEnvironment import MappingRelation

__all__ = ["MapEnvironment"]


class MapEnvironment:
    _config = MappingRelation().map

    @classmethod
    def _command(cls, info):
        """
        远程执行命令
        :param info:
        :return:
        """
        return info

    @classmethod
    def base_url(cls, url):
        """
        获取url信息并执行替换操作
        :param url:
        :return:
        """

        if cls._command(cls._config.BASE_URL):
            u = parse.urlparse(url)
            scheme, netloc, path, params, query = u.scheme, u.netloc, u.path, u.params, u.query
            return f'{
    
    scheme}://{
    
    netloc.replace(netloc, cls._command(cls._config.BASE_URL))}{
    
    path}?{
    
    params}{
    
    query}'
        else:
            return url

    @property
    def base_db(cls):
        """
        获取数据库连接环境账号
        :return:
        """

        return cls._command(cls._config.DATABASE)

    @property
    def host(cls):
        """
        获取域名
        :return:
        """

        return cls._command(cls._config.HOST)

    @property
    def headers(cls):
        """
        获取头部信息
        :return:
        """

        return cls._command(cls._config.HEADERS)

    @property
    def yaml_path(cls):
        """
        读取yaml文件路径
        :return:
        """

        return cls._command(cls._config.YAML_PATH)

    @property
    def lms_logging(cls):
        """
        读取日志配置
        :return:
        """

        return cls._command(cls._config.LMS_LOGGING)

if __name__ == '__main__':
    print(MapEnvironment().host)

这里处理完成后,各处需要参数的类或函数,就直接引入这个类,拿对应的数据即可。

需要注意的是,如果你settings.py配置文件中需要增加新参数,就得在这两个.py文件中进行增加获取数据的方法,不然就是只是增加,没有起到任何作用。

日志配置

日志的配置也是根据上述两个类,读取到settings.py配置文件的日志配置(这里的日志配置,官网有详细介绍,也是减少代码的一种好处,在公众号中也写了该文章,有兴趣的可以翻阅下):

# apiTest/common/logLogging.py

import logging.config
from common.mapMnvironment import MapEnvironment


class LogLogging:
    _logging_conf = MapEnvironment().lms_logging

    def __init__(self):
        logging.config.dictConfig(self._logging_conf)
        self.logger = logging.getLogger()
        self.logger.setLevel(logging.ERROR)

    @property
    def get_logger(self):
        return self.logger


do_logger = LogLogging().get_logger

封装的一个日志获取类,代码和配置作了分离,是不是看起来都简洁了呢,哈哈…

发送企业微信报告

import jenkins
import requests
from functools import partialmethod
from common.mapMnvironment import MapEnvironment


class WeChat:
    _map = MapEnvironment()

    @classmethod
    def _message_info(cls, project, end, total, passing, succeed, failing, error, address: str):
        """
        需要发送到企业微信的文案信息
        :param project:         项目名称
        :param end:             指定端[web、app、h5]
        :param total:           总计
        :param passing:         通过率
        :param succeed:         通过数
        :param failing:         失败数
        :param error:           错误数
        :param address:         链接地址->放一个链接信息
        :return:                返回data信息
        """

        data = {
    
    
            "msgtype": "markdown",  # 消息类型,此时固定为markdown
            "markdown": {
    
    
                "content": "#### **提醒!自动化测试反馈**\n###### **请相关同事注意,及时跟进!**\n"
                           "> 项目名称:<font color=\"comment\">{}</font> \n"
                           "> 测试用例总数:<font color=\"comment\">{}</font>,测试用例通过率:<font color=\"comment\">{}</font>\n"
                           "> **--------------------运行详情--------------------**\n"
                           "**环境:**<font color=\"comment\"> {} </font>,**端:**<font color=\"comment\">{}</font>\n"
                           "> **成功数:**<font color=\"comment\">{}</font>,**失败数:**<font color=\"comment\">{}</font>,"
                           " **错误数:**<font color=\"comment\">{}</font>\n"
                           "> **报告链接:** [jenkins测试报告,鼠标点击此处查看]({})".format(project, total, passing,
                                                                           cls._map.environment, end, succeed, failing,
                                                                           error, address)
                # 加粗:**需要加粗的字**
                # 引用:> 需要引用的文字
                # 字体颜色(只支持3种内置颜色)
                # 标题 (支持1至6级标题,注意#与文字中间要有空格)
                # 绿色:info、灰色:comment、橙红:warning
            }
        }
        return data

    @classmethod
    def send_message(cls, project, end, total, passing, succeed, failing, error, address):
        """
        请求发送接口
        :param project:         项目名称
        :param end:             指定端,管理端、APP端等
        :param total:           总计
        :param passing:         通过率
        :param succeed:         通过数
        :param failing:         失败数
        :param error:           错误数
        :param address:         链接地址->放一个链接信息
        :return:
        """
        # 获取报告文案信息
        data = cls._message_info(project, end, total, passing, succeed, failing, error, address)
        # 请求接口,开始发送请求
        with requests.Session() as session:
            response = session.post(url=cls._map.wechat, json=data, verify=False)
        return response.json()

这个发送企业微信报告,因为牵扯到项目的一些东西,只提供参考,上述两个方法稍微修改下即可使用。

以上总结或许能帮助到你,或许帮助不到你,但还是希望能帮助到你,如有疑问、歧义,直接私信留言会及时修正发布;非常期待你的赞赏、点赞、在看+分享哟,谢谢!

下面是一份配套资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!
在这里插入图片描述
这些都可以以在公众号:伤心的辣条 ! 免费领取,还有一份216页软件测试工程师面试宝典文档资料。以及相对应的视频学习教程免费分享!,其中资料包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。

学习不要孤军奋战,最好是能抱团取暖,相互成就一起成长,群众效应的效果是非常强大的,大家一起学习,一起打卡,会更有学习动力,也更能坚持下去。你可以加入我们的测试技术交流扣扣群:914172719(里面有各种软件测试资源和技术讨论)

喜欢软件测试的小伙伴们,如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!


好文推荐

转行面试,跳槽面试,软件测试人员都必须知道的这几种面试技巧!

面试经:一线城市搬砖!又面软件测试岗,5000就知足了…

面试官:工作三年,还来面初级测试?恐怕你的软件测试工程师的头衔要加双引号…

什么样的人适合从事软件测试工作?

那个准点下班的人,比我先升职了…

测试岗反复跳槽,跳着跳着就跳没了…

猜你喜欢

转载自blog.csdn.net/AI_Green/article/details/121541380