2.7 pytest自动化代码优化

基于上一章的动态生成优化

main.py

import os
from config.config import setting
from utils.template import Template
from utils.md5 import Md5
import pytest
from utils.type_check import CheckType


def run():
    data = os.listdir('data')
    m = Md5('case', 'log', 'case_md5.json')
    n = Md5('utils', 'log', 'template_md5.json')
    filter_list = m.filter()
    utils_list = n.filter()
    if 'template.py' not in utils_list:
        filter_list = []
        n.write_md5()
    for i in data:
        file_path = 'data' + '/' + i
        if os.path.isfile(file_path):
            temp = 'test_' + i
            if temp not in filter_list:
                Template.create_test_file(file_path, 'case')
    m.write_md5()


if __name__ == "__main__":
    import sys

    CheckType.check('data', Template)
    if sys.argv[1] == 'dev':
        setting['baseUrl'] = setting['dev']
    elif sys.argv[1] == 'test':
        setting['baseUrl'] = setting['test']
    elif sys.argv[1] == 'prd':
        setting['baseUrl'] = setting['prd']
    else:
        raise Exception("the command must be like 'python main.py dev | test | prd'")
    run()
    pytest.main(['-s', '--alluredir=results'])
    os.system('allure generate --clean ./results/ -o ./report/')
    os.system('allure open -h 127.0.0.1 -p 8883 ./report/')

utils/type_check.py

import json
import os
from pathlib import Path


class CheckType:

    @staticmethod
    def check(dir_path, fn):
        for file_path in Path(dir_path).iterdir():
            if file_path.is_file() and fn.check_todo_file(file_path) is False:
                import_name = file_path.stem + '_cfg'
                file = file_path.stem
                try:
                    module = __import__(f'data.{file}', fromlist=[f'{import_name}'])
                    cfg = module.__getattribute__(import_name)
                    if not isinstance(cfg, list):
                        raise TypeError(f"Message: the type of <{cfg}> must be list")
                    elif len(cfg) == 0:
                        raise TypeError(f"Message: the type of <{cfg}> can't be empty")
                    else:
                        for j in cfg:
                            if not isinstance(j.get('config'), dict):
                                raise TypeError(f"Message: the attribute <config> of <{import_name}> must be exist "
                                                f"and its type must be dict")
                            elif not isinstance(j.get('req_extract'), (list, type(None))):
                                raise TypeError(f"Message: the attribute <req_extract> of <{import_name}> must be "
                                                f"list or None")
                            elif not isinstance(j.get('res_extract'), (list, type(None))):
                                raise TypeError(f"Message: the attribute <res_extract> of <{import_name}> must be "
                                                f"list or None")
                            elif not isinstance(j.get('as'), (dict, type(None))):
                                raise TypeError(f"Message: the attribute <as> of <{import_name}> must be dict or "
                                                f"None")
                            elif not isinstance(j.get('assert'), dict):
                                raise TypeError(f"Message: the attribute <assert> of <{import_name}> must be exist "
                                                f"and its type must be dict")
                except ModuleNotFoundError as m:
                    print(f'''Message: The required variable <{import_name}> was not found in the file <{file_path.name}>,
Example: the file name is <homepage.py>, the variable name should be <homepage_cfg>
                    ''')

utils/template.py

import os


class Template:
    @staticmethod
    def check_todo_file(file_path: str) -> bool:
        """
        检查文件内容中是否包含 '# TODO' 字符串

        Args:
            file_path (str): 文件路径

        Returns:
            bool: 如果包含 '# TODO' 字符串则返回 True,否则返回 False
        """
        with open(file_path, mode='r+', encoding='utf-8') as file:
            return '# TODO' in file.read()

    @staticmethod
    def create_test_file(file_path: str, target_path: str) -> None:
        """
        创建测试文件

        Args:
            file_path (str): 文件路径
            target_path (str): 目标路径
        """
        if Template.check_todo_file(file_path):
            print(f'Message: 发现 <TODO> 标记,文件 <{file_path}> 尚未完成')
            return

        file_name = os.path.basename(file_path).replace('.py', '')
        import_name = f'{file_name}_cfg'
        test_file_path = os.path.join(target_path, f'test_{file_name}.py')

        with open(test_file_path, mode='w+', encoding='utf-8') as file:
            file.write(f'''import pytest
import allure
from utils.http_request import http_request
from data.{file_name} import {import_name}
from utils.parse import parse
from utils.compare import assert_http_response
from utils.format import format_string

store = {{}}


@allure.suite('{file_name}')
class Test_{file_name.capitalize()}:

    @allure.sub_suite('{import_name}')
    @pytest.mark.parametrize('cfg', {import_name})
    def test_{file_name}(self, getCookie, cfg):  
        format_string(cfg, store)
        allure.dynamic.title(cfg['name'])
        allure.dynamic.parameter('cfg', cfg)
        cfg['config']['headers']['Cookie'] = getCookie
        res = http_request(cfg['config'])
        allure.dynamic.description(res.text)
        parse(cfg, res, store)
        assert_http_response(cfg['assert'], res.json())
''')
        print(f"Message: 文件 <{test_file_path}> 创建成功")

utils/md5.py

import hashlib
import json
import os
from json import JSONDecodeError


class Md5:
    def __init__(self, dir_path, md5_path, file_name):
        self.dir_path = dir_path  # 目录路径
        self.md5_path = md5_path  # MD5文件路径
        self.file_name = file_name  # MD5文件名
        if not os.path.exists(md5_path):
            os.mkdir(md5_path)  # 如果MD5文件路径不存在,则创建该路径
        file_path = os.path.join(md5_path, file_name)
        if not os.path.exists(file_path):
            open(file_path, mode='w+', encoding='utf-8').close()  # 如果MD5文件不存在,则创建该文件

    def generate_md5(self):
        temp = {}
        # 如果dir_path是文件而不是目录,则抛出IOError异常
        if os.path.isfile(self.dir_path):
            raise IOError(f'Message: parameter <dir_path:{self.dir_path}> must be directory')
        else:
            dir_list = os.listdir(self.dir_path)  # 获取目录下的文件列表
            if len(dir_list) != 0:
                for i in dir_list:
                    md5 = hashlib.md5()  # 创建MD5对象
                    file_path = os.path.join(self.dir_path, i)  # 获取文件路径
                    if os.path.isfile(file_path):  # 如果是文件
                        with open(file_path, mode='r', encoding='utf-8') as f:
                            md5.update(f.read().encode(encoding='utf-8'))  # 更新MD5值
                            hex_md5 = md5.hexdigest()  # 获取MD5值
                            temp[i] = hex_md5  # 将文件名和MD5值添加到字典中
            return temp  # 返回字典

    def write_md5(self):
        file_path = os.path.join(self.md5_path, self.file_name)
        # 将generate_md5()生成的字典写入到文件中
        json.dump(self.generate_md5(), open(file_path, mode='w+', encoding='utf-8'))

    def read_md5(self):
        file_path = os.path.join(self.md5_path, self.file_name)
        try:
            with open(file_path, mode='r', encoding='utf-8') as f:
                # 读取文件中的json数据并返回
                return json.load(f)
        except JSONDecodeError:
            # 如果文件中的json数据解析失败,则返回空字典
            return {}

    def filter(self):
        old_md5 = self.read_md5()  # 获取旧的MD5值
        new_md5 = self.generate_md5()  # 获取新的MD5值
        # 返回新旧md5值相同的文件名列表
        return [k for k, v in new_md5.items() if k in old_md5 and v == old_md5[k]]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值