예제 #1
0
파일: db.py 프로젝트: heyeping/apiTest
class DB:
    mysql = ReadFile.read_config('$.database')

    def __init__(self):
        """初始化连接Mysql"""
        self.connection = pymysql.connect(
            host=self.mysql.get('host', 'localhost'),
            port=self.mysql.get('port', 3306),
            user=self.mysql.get('user', 'root'),
            password=self.mysql.get('password', '123456'),
            db=self.mysql.get('db_name', 'test'),
            charset=self.mysql.get('charset', 'utf8mb4'),
            cursorclass=pymysql.cursors.DictCursor
        )

    def fetch_one(self, sql: str) -> object:
        """查询数据,查一条"""
        with self.connection.cursor() as cursor:
            cursor.execute(sql)
            result = cursor.fetchone()
            # 使用commit解决查询数据出现概率查错问题
            self.connection.commit()
        return result

    def close(self):
        """关闭数据库连接"""
        self.connection.close()
예제 #2
0
class BaseRequest(object):
    session = None

    @classmethod
    def get_session(cls):
        if cls.session is None:
            cls.session = requests.Session()
        return cls.session

    @classmethod
    def send_request(cls, case: list, env: str = 'dev') -> object:
        """处理case数据,转换成可用数据发送请求
        :param case: 读取出来的每一行用例内容,可进行解包
        :param env: 环境名称 默认使用config.yaml server下的 dev 后面的基准地址
        return: 响应结果, 预期结果
        """
        case_number, case_title, path, token, method, parametric_key, file_obj, data, sql, expect, is_save = case
        logger.debug(
            f"用例进行处理前数据: \n 接口路径: {path} \n 请求参数: {data} \n 后置sql: {sql} \n 预期结果: {expect} \n 保存响应: {is_save}"
        )
        # allure报告 用例标题
        allure_title(case_title)
        # 处理url、header、data、file、的前置方法
        url = ReadFile.read_config(
            f'$.server.{env}') + DataProcess.handle_path(path)
        allure_step('请求地址', url)
        header = DataProcess.handle_header(token)
        allure_step('请求头', header)
        data = DataProcess.handle_data(data)
        allure_step('请求参数', data)
        file = DataProcess.handler_files(file_obj)
        allure_step('上传文件', file_obj)
        # 发送请求
        res = cls.send_api(url, method, parametric_key, header, data, file)
        allure_step('响应耗时(s)', res.elapsed.total_seconds())
        allure_step('响应内容', res.json())
        # 响应后操作
        if token == '写':
            DataProcess.have_token['Authorization'] = extractor(
                res.json(), ReadFile.read_config('$.expr.token'))
            allure_step('请求头中添加Token', DataProcess.have_token)
        # 保存用例的实际响应
        if is_save == "是":
            DataProcess.save_response(case_number, res.json())
        allure_step('存储实际响应', DataProcess.response_dict)
        return res.json(), expect, sql
예제 #3
0
class DataClearing:
    settings = ReadFile.read_config('$.database')
    server_settings = settings.get('ssh_server')
    server = None

    # 导出的sql文件名称及后缀
    file_name = f"{settings.get('db_name')}_{datetime.now().strftime('%Y-%m-%dT%H_%M_%S')}.sql"

    @classmethod
    def server_init(cls, settings=settings, server_settings=server_settings):
        cls.server = ServerTools(
            host=settings.get('host'),
            port=server_settings.get('port'),
            username=server_settings.get('username'),
            password=server_settings.get('password'),
            private_key_file=server_settings.get('private_key_file'),
            privat_passowrd=server_settings.get('privat_passowrd'))
        # 新建backup_sql文件夹在服务器上,存放导出的sql文件
        cls.server.execute_cmd("mkdir backup_sql")

    @classmethod
    def backup_mysql(cls):
        """
        备份数据库, 会分别备份在数据库所在服务器的/root/backup_sql/目录下, 与当前项目文件目录下的 backup_sqls
        每次备份生成一个数据库名_当前年_月_日T_时_分_秒, 支持linux 服务器上安装的mysql服务(本人未调试),以及linux中docker部署的mysql备份
        """
        if cls.server_settings.get('mysql_container') is None:
            cmd = f"mysqldump -h127.0.0.1 -u{cls.settings.get('username')} -p{cls.settings.get('password')} {cls.settings.get('db_name')} > {cls.file_name}"
        else:
            # 将mysql服务的容器中的指定数据库导出, 参考文章
            # https://www.cnblogs.com/wangsongbai/p/12666368.html
            cmd = f"docker exec -i {cls.server_settings.get('mysql_container')} mysqldump -h127.0.0.1 -u{cls.settings.get('user')} -p{cls.settings.get('password')} {cls.settings.get('db_name')} > /root/backup_sql/{cls.file_name}"
        cls.server.execute_cmd(cmd)
        cls.server.files_action(0,
                                f"{cls.server_settings.get('sql_data_file')}",
                                f"/root/backup_sql/{cls.file_name}")

    @classmethod
    def recovery_mysql(cls,
                       sql_file: str = file_name,
                       database: str = settings.get('db_name')):
        """
        恢复数据库, 从服务器位置(/root/backup_sql/) 或者本地(../backup_sqls)上传, 传入的需要是.sql文件
        :param sql_file: .sql数据库备份文件, 默认就是导出的sql文件名称, 默认文件名称是导出的sql文件
        :param database: 恢复的数据库名称,默认是备份数据库(config.yaml中的db_name)
        """
        result = cls.server.execute_cmd(f"ls -l /root/backup_sql/{sql_file}")
        if "No such file or directory" in result:
            # 本地上传
            cls.server.files_action(1, f"../backup_sqls/{sql_file}",
                                    "/root/backup_sql/")
        cmd = f"docker exec -i {cls.server_settings.get('mysql_container')} mysql -u{cls.settings.get('user')} -p{cls.settings.get('password')} {database} < /root/backup_sql/{sql_file}"
        cls.server.execute_cmd(cmd)

    @classmethod
    def close_client(cls):
        cls.server.ssh_close()
예제 #4
0
 def handle_path(cls, path_str: str, env: str) -> str:
     """路径参数处理
     :param path_str: 带提取表达式的字符串 /&$.case_005.data.id&/state/&$.case_005.data.create_time&
     :param env: 环境名称, 对应的是环境基准地址
     上述内容表示,从响应字典中提取到case_005字典里data字典里id的值,假设是500,后面&$.case_005.data.create_time& 类似,最终提取结果
     return  /511/state/1605711095
     """
     # /&$.case.data.id&/state/&$.case_005.data.create_time&
     url = ReadFile.read_config(f'$.server.{env}') + rep_expr(
         path_str, cls.response_dict)
     allure_step_no(f'请求地址: {url}')
     return url
예제 #5
0
class DB:
    mysql = ReadFile.read_config('$.database')

    def __init__(self):
        """
        初始化数据库连接,并指定查询的结果集以字典形式返回
        """
        self.connection = pymysql.connect(
            host=self.mysql['host'],
            port=self.mysql['port'],
            user=self.mysql['user'],
            password=self.mysql['password'],
            db=self.mysql['db_name'],
            charset=self.mysql.get('charset', 'utf8mb4'),
            cursorclass=pymysql.cursors.DictCursor)

    def execute_sql(self, sql: str) -> Union[dict, None]:
        """
        执行sql语句方法,查询所有结果的sql只会返回一条结果(
        比如说: 使用select * from cases , 结果将只会返回第一条数据    {'id': 1, 'name': 'updatehahaha', 'path': None, 'body': None, 'expected': '{"msg": "你好"}', 'api_id': 1, 'create_at': '2021-05-17 17:23:54', 'update_at': '2021-05-17 17:23:54'}

        ),支持select, delete, insert, update
        :param sql: sql语句
        :return: select 语句 如果有结果则会返回 对应结果字典,delete,insert,update 将返回None
        """
        with self.connection.cursor() as cursor:
            cursor.execute(sql)
            result = cursor.fetchone()
            # 使用commit解决查询数据出现概率查错问题
            self.connection.commit()
            return self.verify(result)

    def verify(self, result: dict) -> Union[dict, None]:
        """验证结果能否被json.dumps序列化"""
        # 尝试变成字符串,解决datetime 无法被json 序列化问题
        try:
            json.dumps(result)
        except TypeError:  # TypeError: Object of type datetime is not JSON serializable
            for k, v in result.items():
                if isinstance(v, datetime):
                    result[k] = str(v)
        return result

    def close(self):
        """关闭数据库连接"""
        self.connection.close()
예제 #6
0
    # def __init__(self):
    #     """初始化连接Mysql"""
    #     self.connection = pymysql.connect(
    #         host=self.mysql.get('host', 'localhost'),
    #         port=self.mysql.get('port', 3306),
    #         user=self.mysql.get('user', 'root'),
    #         password=self.mysql.get('password', '123456'),
    #         db=self.mysql.get('db_name', 'test'),
    #         charset=self.mysql.get('charset', 'utf8mb4'),
    #         cursorclass=pymysql.cursors.DictCursor
    #     )

    def fetch_one(self, sql: str) -> object:
        """查询数据,查一条"""
        with self.connection.cursor() as cursor:
            cursor.execute(sql)
            result = cursor.fetchone()
            # 使用commit解决查询数据出现概率查错问题
            self.connection.commit()
        return result

    def close(self):
        """关闭数据库连接"""
        self.connection.close()


if __name__ == '__main__':
    print(ReadFile.read_config('$.database'))
    DB()
예제 #7
0
@file: test_api.py
@ide: PyCharm
@time: 2020/11/22
@desc: 测试方法
"""
import os
import shutil

import pytest

from tools import logger
from api.base_requests import BaseRequest
from tools.data_process import DataProcess
from tools.read_file import ReadFile

report = ReadFile.read_config('$.file_path.report')
logfile = ReadFile.read_config('$.file_path.log')
# 读取excel数据对象
cases = ReadFile.read_testcase()


class TestApi:
    @classmethod
    def run(cls):
        if os.path.exists('../report'):
            shutil.rmtree(path='../report')
        logger.add(logfile, enqueue=True, encoding='utf-8')
        logger.info('开始测试...')
        pytest.main(args=[f'--alluredir={report}/data'])
        os.system(f'allure generate {report}/data -o {report}/html --clean')
        logger.success('报告已生成')
예제 #8
0
@pytest.fixture(scope="session")
def data_clearing():
    """数据清洗"""
    DataClearing.server_init()
    # 1. 备份数据库
    DataClearing.backup_mysql()
    yield
    # 2. 恢复数据库
    DataClearing.recovery_mysql()
    DataClearing.close_client()


# 若不需要数据清洗功能,请把get_db()入参拿掉
@pytest.fixture(scope="session")
def get_db(data_clearing):
    """关于其作用域请移步查看官方文档"""
    try:
        db = DB()
        yield db
    finally:
        db.close()


@pytest.fixture(params=ReadFile.read_testcase())
def cases(request):
    """用例数据,测试方法参数入参该方法名 cases即可,实现同样的参数化
    目前来看相较于@pytest.mark.parametrize 更简洁。
    """
    return request.param
예제 #9
0
class DataProcess:
    response_dict = {}
    header = ReadFile.read_config('$.request_headers')
    have_token = header.copy()

    @classmethod
    def save_response(cls, key: str, value: object) -> None:
        """
        保存实际响应
        :param key: 保存字典中的key,一般使用用例编号
        :param value: 保存字典中的value,使用json响应
        """
        cls.response_dict[key] = value
        logger.info(f'添加key: {key}, 对应value: {value}')

    @classmethod
    def handle_path(cls, path_str: str) -> str:
        """路径参数处理
        :param path_str: 带提取表达式的字符串 /&$.case_005.data.id&/state/&$.case_005.data.create_time&
        上述内容表示,从响应字典中提取到case_005字典里data字典里id的值,假设是500,后面&$.case_005.data.create_time& 类似,最终提取结果
        return  /511/state/1605711095
        """
        # /&$.case.data.id&/state/&$.case_005.data.create_time&
        return rep_expr(path_str, cls.response_dict)

    @classmethod
    def handle_header(cls, token: str) -> dict:
        """处理header
        :param token: 写: 写入token到header中, 读: 使用带token的header, 空:使用不带token的header
        return
        """
        if token == '读':
            return cls.have_token
        else:
            return cls.header

    @classmethod
    def handler_files(cls, file_obj: str) -> object:
        """file对象处理方法
        :param file_obj: 上传文件使用,格式:接口中文件参数的名称:"文件路径地址"/["文件地址1", "文件地址2"]
        实例- 单个文件: &file&D:
        """
        if file_obj == '':
            return
        for k, v in convert_json(file_obj).items():
            # 多文件上传
            if isinstance(v, list):
                files = []
                for path in v:
                    files.append((k, (open(path, 'rb'))))
            else:
                # 单文件上传
                files = {k: open(v, 'rb')}
        return files

    @classmethod
    def handle_data(cls, variable: str) -> dict:
        """请求数据处理
        :param variable: 请求数据,传入的是可转换字典/json的字符串,其中可以包含变量表达式
        return 处理之后的json/dict类型的字典数据
        """
        if variable == '':
            return
        data = rep_expr(variable, cls.response_dict)
        variable = convert_json(data)
        return variable

    @classmethod
    def handle_sql(cls, sql: str, db: object):
        """处理sql,并将结果写到响应字典中"""
        if sql not in ['no', '']:
            sql = rep_expr(sql, DataProcess.response_dict)
        else:
            sql = None
        allure_step('运行sql', sql)
        logger.info(sql)
        if sql is not None:
            # 查后置sql
            result = db.fetch_one(sql)
            allure_step('sql执行结果', {"sql_result": result})
            logger.info(f'结果:{result}')
            if result is not None:
                # 将查询结果添加到响应字典里面,作用在,接口响应的内容某个字段 直接和数据库某个字段比对,在预期结果中
                # 使用同样的语法提取即可
                DataProcess.response_dict.update(result)

    @classmethod
    def assert_result(cls, response: dict, expect_str: str):
        """ 预期结果实际结果断言方法
        :param response: 实际响应结果
        :param expect_str: 预期响应内容,从excel中读取
        return None
        """
        # 后置sql变量转换
        expect_str = rep_expr(expect_str, DataProcess.response_dict)
        expect_dict = convert_json(expect_str)
        index = 0
        for k, v in expect_dict.items():
            # 获取需要断言的实际结果部分
            actual = extractor(response, k)
            index += 1
            logger.info(
                f'第{index}个断言,实际结果:{actual} | 预期结果:{v} \n断言结果 {actual == v}')
            allure_step(f'第{index}个断言', f'实际结果:{actual} = 预期结果:{v}')
            try:
                assert actual == v
            except AssertionError:
                raise AssertionError(
                    f'第{index}个断言失败 -|- 实际结果:{actual} || 预期结果: {v}')
예제 #10
0
# -*- coding: utf-8 -*-
# @Time    : 2021/5/2 22:26
# @Author  : RanyLra
# @Wechat  : RanY_Luck
# @File    : run.py
import os
import shutil
from test.conftest import pytest
from tools import logger
from tools.read_file import ReadFile
from tools.send_email import EmailServe

report = ReadFile.read_config('$.file_path.report')
logfile = ReadFile.read_config('$.file_path.log')
file_path = ReadFile.read_config('$.file_path')
s_email = ReadFile.read_config('$.email')


def run():
    if os.path.exists('report/'):
        shutil.rmtree(path='report/')
    logger.add(logfile, enqueue=True, encoding='utf-8')
    logger.info("""
                 _    _         _      _____         _   
  __ _ _ __ (_)  / \\  _   _| |_ __|_   _|__  ___| |_ 
 / _` | '_ \\| | / _ \\| | | | __/ _ \\| |/ _ \\/ __| __|
| (_| | |_) | |/ ___ \\ |_| | || (_) | |  __/\\__ \\ |_ 
 \\__,_| .__/|_/_/   \\_\\__,_|\\__\\___/|_|\\___||___/\\__|
      |_|                                            
      Starting      ...     ...     ...
    """)
예제 #11
0
파일: run.py 프로젝트: heyeping/apiTest
"""
@project: apiTest
@author: Tamia
@file: run.py
@ide: PyCharm
@time: 2020/12/16
@desc: 运行文件
"""

import os
import shutil
from test.conftest import pytest
from tools import logger
from tools.read_file import ReadFile

report = ReadFile.read_config('$.file_path.report')
logfile = ReadFile.read_config('$.file_path.log')


def run():
    if os.path.exists('report/'):
        shutil.rmtree(path='report/')
    logger.add(logfile, enqueue=True, encoding='utf-8')
    logger.info("""
                 _    _         _      _____         _   
  __ _ _ __ (_)  / \  _   _| |_ __|_   _|__  ___| |_ 
 / _` | '_ \| | / _ \| | | | __/ _ \| |/ _ \/ __| __|
| (_| | |_) | |/ ___ \ |_| | || (_) | |  __/\__ \ |_ 
 \__,_| .__/|_/_/   \_\__,_|\__\___/|_|\___||___/\__|
      |_|                                            
      Starting      ...     ...     ...
예제 #12
0
class DataProcess:
    response_dict = {}
    header = ReadFile.read_config('$.request_headers')

    @classmethod
    def save_response(cls, key: str, value: object) -> None:
        """
        保存实际响应
        :param key: 保存字典中的key,一般使用用例编号
        :param value: 保存字典中的value,使用json响应
        """
        cls.response_dict[key] = value
        logger.info(f'添加key: {key}, 对应value: {value}')
        allure_step('存储实际响应', cls.response_dict)

    @classmethod
    def handle_path(cls, path_str: str, env: str) -> str:
        """路径参数处理
        :param path_str: 带提取表达式的字符串 /&$.case_005.data.id&/state/&$.case_005.data.create_time&
        :param env: 环境名称, 对应的是环境基准地址
        上述内容表示,从响应字典中提取到case_005字典里data字典里id的值,假设是500,后面&$.case_005.data.create_time& 类似,最终提取结果
        return  /511/state/1605711095
        """
        # /&$.case.data.id&/state/&$.case_005.data.create_time&
        url = ReadFile.read_config(f'$.server.{env}') + rep_expr(
            path_str, cls.response_dict)
        allure_step_no(f'请求地址: {url}')
        return url

    @classmethod
    def handle_header(cls, header_str: str) -> dict:
        """处理header, 将用例中的表达式处理后 追加到基础header中
        :header_str: 用例栏中的header
        return header:
        """
        if header_str == '':
            header_str = '{}'
        cls.header.update(cls.handle_data(header_str))
        allure_step('请求头', cls.header)
        return cls.header

    @classmethod
    def handler_files(cls, file_obj: str) -> object:
        """file对象处理方法
        :param file_obj: 上传文件使用,格式:接口中文件参数的名称:"文件路径地址"/["文件地址1", "文件地址2"]
        实例- 单个文件: &file&D:
        """
        if file_obj != '':
            for k, v in convert_json(file_obj).items():
                # 多文件上传
                if isinstance(v, list):
                    files = []
                    for path in v:
                        files.append((k, (open(path, 'rb'))))
                else:
                    # 单文件上传
                    files = {k: open(v, 'rb')}
            allure_step('上传文件', file_obj)
            return files

    @classmethod
    def handle_data(cls, variable: str) -> dict:
        """请求数据处理
        :param variable: 请求数据,传入的是可转换字典/json的字符串,其中可以包含变量表达式
        return 处理之后的json/dict类型的字典数据
        """
        if variable != '':
            data = rep_expr(variable, cls.response_dict)
            variable = convert_json(data)
            return variable

    @classmethod
    def handle_sql(cls, sql: str, db: DB):
        """
        处理sql,如果sql执行的结果不会空,执行sql的结果和响应结果字典合并
        :param sql: 支持单条或者多条sql,其中多条sql使用 ; 进行分割
            多条sql,在用例中填写方式如下select * from user; select * from goods 每条sql语句之间需要使用 ; 来分割
            单条sql,select * from user 或者 select * from user;
        :param db: 数据库连接对象
        :return:
        """
        sql = rep_expr(sql, DataProcess.response_dict)

        for sql in sql.split(";"):
            sql = sql.strip()
            if sql == '':
                continue
            # 查后置sql
            result = db.execute_sql(sql)
            allure_step(f'执行sql: {sql}', result)
            logger.info(f'执行sql: {sql} \n 结果: {result}')
            if result is not None:
                # 将查询结果添加到响应字典里面,作用在,接口响应的内容某个字段 直接和数据库某个字段比对,在预期结果中
                # 使用同样的语法提取即可
                DataProcess.response_dict.update(result)

    @classmethod
    def assert_result(cls, response: dict, expect_str: str):
        """ 预期结果实际结果断言方法
        :param response: 实际响应结果
        :param expect_str: 预期响应内容,从excel中读取
        return None
        """
        # 后置sql变量转换
        expect_str = rep_expr(expect_str, DataProcess.response_dict)
        expect_dict = convert_json(expect_str)
        index = 0
        for k, v in expect_dict.items():
            # 获取需要断言的实际结果部分
            actual = extractor(response, k)
            index += 1
            logger.info(
                f'第{index}个断言,实际结果:{actual} | 预期结果:{v} \n断言结果 {actual == v}')
            allure_step(f'第{index}个断言', f'实际结果:{actual} = 预期结果:{v}')
            try:
                assert actual == v
            except AssertionError:
                raise AssertionError(
                    f'第{index}个断言失败 -|- 实际结果:{actual} || 预期结果: {v}')
예제 #13
0
class DataProcess:
    response_dict = {}
    header = ReadFile.read_config('$.request_headers')

    @classmethod
    def save_response(cls, key: str, value: object) -> None:
        """
        保存实际响应
        :param key: 保存字典中key,一般使用用例编号
        :param value: 保存字典中的value,使用json献映
        :return: 返回最终保存结果
        """
        cls.response_dict[key] = value
        logger.info(f'添加key:{key},对应value:{value}')

    @classmethod
    def handle_path(cls, path_str: str) -> str:
        """
        路径参数处理
        :param path_str: 带提取表达式的字符串 /&$.case_005_data.id&/stats/&$.case_005.data.create_time&
        上述内容解析为:从响应字典中提取到case_005字典里datazi字典里的id的值,假设是500,后面&$.case_005.data.create_time& 类似,最终提取结果为:
        :return: /500/state/123456
        """
        # /&$.case_005.data.id&/state/&$.case_005.data.create_time&
        return rep_expr(path_str, cls.response_dict)

    @classmethod
    def handle_header(cls, header_str: str) -> dict:
        """
        处理header,将用例中的表达式处理后,追加到基础header中
        :param header_str: 用例栏中的header
        :return: 返回header
        """
        if header_str == '':
            header_str = '{}'
        cls.header.update(cls.handle_data(header_str))
        return cls.header

    @classmethod
    def handler_files(cls, file_obj: str) -> object:
        """
        file对象处理方法
        :param file_obj: 上传文件使用,格式:接口中文件参数的名称:"文件路径地址"/["文件地址1","文件地址2"]
        :return: {"files":["C:\\Users\\ranyong\\Desktop\\b.jpg", "C:\\Users\\ranyong\\Desktop\\c.jpg"]}
        """
        if file_obj == '':
            return
        for k, v in convert_json(file_obj).items():
            # 多文件上传
            if isinstance(v, list):
                files = []
                for path in v:
                    files.append((k, (open(path, 'rb'))))
            else:
                # 单文件上传
                files = {k: open(v, 'rb')}
        return files

    @classmethod
    def handle_data(cls, variable: str) -> dict:
        """
        请求数据处理
        :param variable: 请求数据,传入的是可换成字典/json的字符串,其中可以包含变量表达式
        :return: 处理之后的json/dict类型的字典数据
        """
        if variable == '':
            return
        data = rep_expr(variable, cls.response_dict)
        variable = convert_json(data)
        return variable

    @classmethod
    def handle_sql(cls, sql: str, db: object):
        """
        处理sql,并将结果写在响应字典中
        :param sql: sql语句
        :param db: 数据库名
        :return: 写到响应字典中
        """
        if sql not in ['no', '']:
            sql = rep_expr(sql, DataProcess.response_dict)
        else:
            sql = None
        allure_step('运行sql', sql)
        logger.info(sql)
        if sql is not None:
            # 查后置sql
            result = db.fetch_one(sql)
            allure_step('sql执行结果', result)
            logger.info(f'结果:{result}')
            if result is not None:
                # 将查询结果添加到响应字典里面,作用在接口响应的内容某个字段,直接和数据库某个字段比对,在预期结果中
                # 使用同样的语法提取即可
                DataProcess.response_dict.update(result)

    @classmethod
    def assert_result(cls, response: dict, expect_str: str):
        """
        预期结果实际结果断言方式
        :param response: 实际响应结果
        :param expect_str: 预期响应内容,从excel中读取
        :return: None
        """
        # 后置sql变量控制
        expect_str = rep_expr(expect_str, DataProcess.response_dict)
        expect_dict = convert_json(expect_str)
        index = 0
        for k, v in expect_dict.items():
            # 获取需要断言的实际结果部分
            actual = extractor(response, k)
            index += 1
            logger.info(f'第{index}个断言',
                        f'实际结果:{actual} || 预期结果:{v} \n断言结果 {actual == v}')
            allure_step(f'第{index}个断言', f'实际结果:{actual}=预期结果:{v}')
            try:
                assert actual == v
            except AssertionError:
                raise AssertionError(
                    f'第{index}个断言失败 -|- 实际结果:{actual} || 你的预期结果: {v}')
예제 #14
0
@file: run.py
@ide: PyCharm
@time: 2020/12/16
@github: https://github.com/zy7y
@site: https://cnblogs.com/zy7y
@desc: 运行文件
"""

import os
import shutil
from test.conftest import pytest
from tools import logger
from tools.read_file import ReadFile
from tools.send_email import EmailServe

file_path = ReadFile.read_config('$.file_path')
email = ReadFile.read_config('$.email')


def run():
    if os.path.exists('report/'):
        shutil.rmtree(path='report/')
    logger.add(file_path['log'], enqueue=True, encoding='utf-8')
    logger.info("""
                 _    _         _      _____         _
  __ _ _ __ (_)  / \\  _   _| |_ __|_   _|__  ___| |_
 / _` | '_ \\| | / _ \\| | | | __/ _ \\| |/ _ \\/ __| __|
| (_| | |_) | |/ ___ \\ |_| | || (_) | |  __/\\__ \\ |_
 \\__,_| .__/|_/_/   \\_\\__,_|\\__\\___/|_|\\___||___/\\__|
      |_|
      Starting      ...     ...     ...
예제 #15
0
class DataProcess:
    response_dict = {}
    header = ReadFile.read_config('$.request_headers')
    have_token = header.copy()

    @classmethod
    def save_response(cls, key: str, value: object) -> None:
        """
        保存实际响应
        :param key: 保存字典中的key,一般使用用例编号
        :param value: 保存字典中的value,使用json响应
        """
        cls.response_dict[key] = value
        logger.info(f'添加key: {key}, 对应value: {value}')

    @classmethod
    def handle_path(cls, path_str: str) -> str:
        """路径参数处理
        :param path_str: 带提取表达式的字符串 /&$.case_005.data.id&/state/&$.case_005.data.create_time&
        上述内容表示,从响应字典中提取到case_005字典里data字典里id的值,假设是500,后面&$.case_005.data.create_time& 类似,最终提取结果
        return  /511/state/1605711095
        """
        # /&$.case.data.id&/state/&$.case_005.data.create_time&
        return rep_expr(path_str, cls.response_dict)

    @classmethod
    def handle_header(cls, token: str) -> dict:
        """处理header
        :param token: 写: 写入token到header中, 读: 使用带token的header, 空:使用不带token的header
        return
        """
        if token == '读':
            return cls.have_token
        else:
            return cls.header

    @classmethod
    def handler_files(cls, file_obj: str) -> object:
        """file对象处理方法
        :param file_obj: 上传文件使用,格式:接口中文件参数的名称:"文件路径地址"/["文件地址1", "文件地址2"]
        实例- 单个文件: &file&D:
        """
        if file_obj == '':
            return
        for k, v in convert_json(file_obj).items():
            # 多文件上传
            if isinstance(v, list):
                files = []
                for path in v:
                    files.append((k, (open(path, 'rb'))))
            else:
                # 单文件上传
                files = {k: open(v, 'rb')}
        return files

    @classmethod
    def handle_data(cls, variable: str) -> dict:
        """请求数据处理
        :param variable: 请求数据,传入的是可转换字典/json的字符串,其中可以包含变量表达式
        return 处理之后的json/dict类型的字典数据
        """
        if variable == '':
            return
        data = rep_expr(variable, cls.response_dict)
        variable = convert_json(data)
        return variable

    @classmethod
    def assert_result(cls, response: dict, expect_str: str):
        """ 预期结果实际结果断言方法
        :param response: 实际响应字典
        :param expect_str: 预期响应内容,从excel中读取
        return None
        """
        expect_dict = convert_json(expect_str)
        index = 0
        for k, v in expect_dict.items():
            actual = extractor(response, k)
            index += 1
            logger.info(
                f'第{index}个断言,实际结果:{actual} | 预期结果:{v} \n断言结果 {actual == v}')
            allure_step(f'第{index}个断言', f'实际结果:{actual} = 预期结果:{v}')
            assert actual == v