如何实现一个业务系统的自动化框架搭建

news2024/11/27 15:29:45

1、框架结构

我在该项目采用的是关键字驱动测试的框架类型。首先创建如下几个目录common(公共模块)、config(公共配置)、logs(运行日志)、reports(测试报告)、resources(测试资源)、testcases(测试用例)、utils(工具脚本)。在接下来的环节我将详细介绍这几个模块的实现。

2、公共配置config 

config文件夹下放有config.ini和conf.py。config.ini用来管理多套测试环境(dev、sit、uat),config.py用来管理项目目录的存取。

# config.ini
[WEB_SIT]
sit = icare
type = uat
sms_url = http://xx.sangfor.com
url = http://xx.sangfor.com
username = user
password = pass
db = sf-icare
db_host = 1.1.1.1
db_port = 3306
db_user = xx
db_pass = xx

[ICARE_DEV]
sit = icare
type = dev
sms_url = http://xx.sangfor.com
url = http://xx.sangfor.com
username = xx
password = xx
db = sf-icare
db_host = 2.2.2.2
db_port = 3306
db_user = xx
db_pass = xx

[ICARE_SIT]
sit = icare
type = sit
sms_url = http://xx.sangfor.com
url = http://xx.sangfor.com
username = xx
password = xx
db = sf-icare
db_host = 3.3.3.3
db_port = 3306
db_user = xx
db_pass = xx

[ICARE_UAT]
sit = icare
type = uat
sms_url = http://xx.sangfor.com
url = http://xx.sangfor.com
username = xx
password = xx
db = sf-icare
db_host = 4.4.4.4
db_port = 3306
db_user = xx
db_pass = xx

[PRM_SIT]
sit = prm
type = sit
url = https://xx.sangfor.com
username = xx
password = xx

[TOKEN]
token = /api/api-auth/oauth/user/token

[HEADERS]
user_agent = Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
authorization = Bearer 4521eb70-8fb2-4747-a512-1d2aed596849

[ICARE_USER]
super_user = 13300,99896,94406,98923,43913,21401

#conf.py
import os
import uuid
from utils.times import dt_strftime


class ConfigManager(object):
    # 项目目录
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


    @property
    def log_file(self):
        """日志目录"""
        log_dir = os.path.join(self.BASE_DIR, 'logs', dt_strftime())
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        return os.path.join(log_dir, '{}.log'.format(dt_strftime('%Y%m%d')))

    @property
    def ini_file(self):
        """配置文件"""
        ini_file = os.path.join(self.BASE_DIR, 'config', 'config.ini')
        if not os.path.exists(ini_file):
            raise FileNotFoundError("配置文件%s不存在!" % ini_file)
        return ini_file

    @property
    def report_dir(self):
        """测试报告目录"""
        report_dir = os.path.join(self.BASE_DIR, 'reports', dt_strftime('%Y%m%d'), str(uuid.uuid1()))
        if not os.path.exists(report_dir):
            os.makedirs(report_dir)
        report_json_dir = os.path.join(report_dir, 'temp_jsonreport')
        report_html_dir = os.path.join(report_dir, 'html')
        if not os.path.exists(report_json_dir):
            os.makedirs(report_json_dir)
        if not os.path.exists(report_html_dir):
            os.makedirs(report_html_dir)
        dir_dict = {'report_json_dir': report_json_dir, 'report_html_dir':report_html_dir}
        return dir_dict


    def json_file(self, json_name):
        """json文件"""
        json_file = os.path.join(self.BASE_DIR, 'resources', json_name)
        if not os.path.exists(json_file):
            raise FileNotFoundError("json文件%s不存在!" % json_file)
        return json_file

    def test_file(self, test):
        """上传下载测试文件"""
        test = os.path.join(self.BASE_DIR, 'resources', test)
        if not os.path.exists(test):
            raise FileNotFoundError("测试文件%s不存在!" % test)
        return test



cm = ConfigManager()
if __name__ == '__main__':
    cm.report_html_dir
    # pass

3、公共模块common

common目录下主要存放着各个业务模块的关键字封装(cass_step)和一些公用的场景,如连接数据库、读取配置文件内容、获取登录用户token、request请求封装。如下摘取片段:

#  question_step.py
  @allure.step("setup:检查问题单基本信息")
    def check_q_info(self, re_info, q_data):
        """
        1、取问题单的基本信息
        2、取提交问题单时填写的基本信息
        3、对比
        :param re_info:get_question_info
        :param q_data: {
            "客户名称": "测试",
            "客户联系人": "小李",
            "客户联系电话": "13343427921",
            "产品线": "aCMP",
            "业务影响": "P21",
            "问题分类": "产品技术问题",
            "问题描述": "描述测试测试测试",
        }
        :return:
        """

        try:
            cust_name = re_info["customerName"]
            contact_name = re_info["contactName"]
            contact_phone = re_info["contactPhoneNumber"]
            product = re_info["mainProductLine"]
            descrip = re_info["questionDescription"]

            cs.assert_result("包含", q_data["客户名称"], cust_name)
            cs.assert_result("等于", contact_name, q_data["客户联系人"])
            cs.assert_result("等于", contact_phone, q_data["客户联系电话"])
            cs.assert_result("等于", product, q_data["产品线"])
            cs.assert_result("等于", descrip, q_data["问题描述"])

        except TypeError:
            pytest.fail("该工单不存在!")
        except AssertionError:
            pytest.fail("检查工单信息和填写不一致!")
# request_url.py
class RequestMain:
    def __init__(self):
        self.session = requests.Session()

    def request_main(self, method, url, params=None, data=None, payloads=None, headers=None, redirects=True, **kwargs):
        """
        :param method: 请求方式
        :param url: 请求地址
        :param params: 字典或bytes,作为参数增加到url中
        :param data: data类型传参,字典、字节序列或文件对象,作为Request的内容
        :param payloads: json传参,作为Request的内容
        :param headers: 请求头,字典
        :param kwargs: 若还有其他的参数,使用可变参数字典形式进行传递
        :return:
        """
        ini = ReadConfig()
        ini_headers = {
            'User-Agent': ini.user_agent,
            'Authorization': ini.auth,
        }
        # log.info(ini)

        if headers is None:
            self.session.headers.update(ini_headers)
        else:
            self.session.headers.update(headers)
        # log.info('正在请求{}接口:{}'.format(method, url))

        try:
            """
            封装request请求,将请求方法、请求地址,请求参数、请求头等信息入参。
            注 :verify: True/False,默认为True,认证SSL证书开关;cert: 本地SSL证书。如果不需要ssl认证,可将这两个入参去掉
                allow_redirects:True/False,默认为True,是启动重定向
            """
            re_data = self.session.request(method, url, params=params, data=data, json=payloads, headers=headers, allow_redirects=redirects, timeout=10, verify=False, **kwargs)
            try:
                log.info(self.session.headers["Content-Type"])
                del self.session.headers['Content-Type']
            except KeyError:
                pass

            if re_data.status_code != 200:
                # 如果重定向,新连接在response headers里
                if re_data.status_code == 302:
                    return re_data.headers
                raise Exception(re_data.text)
            result = re_data.text
            # log.info("请求成功,返回结果{0}".format(result))
            return json.loads(result)
        except asyncio.exceptions.TimeoutError:
            log.error("连接超时!")
            pytest.fail("连接超时")
        except Exception as e:
            log.error("请求失败:{0}".format(e))
            pytest.fail("请求失败:{0}".format(e))

 4、运行日志logs

记录运行过程的日志,用来调试用例。

INFO	2023-09-11 10:32:02,611	[question_step.py:135]	问题单创建成功:Q2023091100004
INFO	2023-09-11 10:32:02,723	[question_step.py:248]	问题单当前状态为{'main_status': 20, 'status': 2010}
INFO	2023-09-11 10:32:02,729	[question_step.py:285]	获取问题创建人为:w13300
INFO	2023-09-11 10:32:02,785	[common_step.py:62]	当前登陆人:w13300
INFO	2023-09-11 10:32:03,035	[conftest.py:71]	恢复配置中...

5、测试资源resources

用来存放测试使用的接口数据json

6、测试用例testcases

存放测试用例(按业务场景串联起来的关键字)

# test_question.py    
    @pytest.mark.smoke
    @allure.feature('问题管理')
    @allure.title('新建问题单自己处理流程')
    def test_question_my(self):
        # 1、手动新建问题单,填写基本信息,选自己处理 - 请求受理,提交
        q_no = qs.create_question(q_info, deal_type={"type": "自己处理", "info": "请求受理"})
        q_data = qs.get_question_info(q_no)
        # 2、检查问题单状态、责任人、问题来源
        status = qs.get_q_status(q_data)
        cs.assert_result("等于", status["status"], ts.trans_question_status("请求受理")[1])
        cs.assert_result("等于", status["main_status"], ts.trans_question_status("请求受理")[0])
        create_user = qs.get_question_handler(q_data, "问题创建人")
        user1 = cs.login_user()["username"]
        cs.assert_result("等于", create_user, user1)
        # 3、检查问题单基本信息,客户名称、产品线、业务影响、版本号、问题描述、问题分类
        qs.check_q_info(q_data, q_info)
        # 4、写进展 - 问题确认解决,检查处理进展,检查短信
        qs.write_next_plan(q_no, "问题确认解决")
        # 5、点击短信里的超链接,检查H5页面
        sms_dict = qs.get_sms_record(q_no)
        cs.assert_result("大于", sms_dict["count"], 0)
        sms_link = sms_dict["content"]
        short_key = qs.request_sms_link(sms_link)
        h5_progress_count = qs.h5_show_progress(short_key)
        cs.assert_result("等于", h5_progress_count, 3)
        # 6、H5页面评价,勾选四星提交,检查后台评价结果
        score = 8
        qs.sms_evaluation(q_no, score)
        web_score = qs.get_eval_result(q_no)
        cs.assert_result("等于", score, web_score)

 7、测试报告allure

使用了allure报告,看起来更美观。

8、工具脚本utils

为了测试用例的代码更简洁美观,将处理数据、字段取值转换等单独封装起来。

9、运行自动化测试

创建解析器,自定义命令行参数,让执行更简单

# main.py
def get_command():
    """
    创建一个解析器,解析命令行参数
    :return: args
    """
    parser = argparse.ArgumentParser(description="解析命令行参数")
    parser.add_argument("--env", "-e", help="环境配置-dev/sit/uat")
    parser.add_argument("--module", "-m", help="用例模块-问题模块/项目模块")
    parser.add_argument("--smoke", "-s", help="冒烟执行-1")
    parser.add_argument("--test", "-t", help="测试调试-1")
    args = parser.parse_args()
    return args


    # 命令行执行python .\main.py -e sit -m 问题模块 -s 1
    # 参数-e对应测试环境:可输入dev/sit/uat,不填默认sit
    # 参数-m对应测试模块:可输入问题模块/项目模块,不填默认执行全部
    # 参数-s对应冒烟测试:可输入1,不填默认执行全部

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1052822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端的多种克隆方式和注意事项

克隆的意义和常见场景: 意义: 保证原数据的完整性和独立性常见场景: 复制数据, 函数入参, class构造函数等 浅克隆: 对象常用的浅克隆 es6扩展运算符...Object.assign 数组常用的浅克隆 es6的扩展运算符...slice>arr.slice(0)[].concat 深度克隆: 克隆对象的每个层级如…

YOLOv8改进算法之添加CA注意力机制

1. CA注意力机制 CA(Coordinate Attention)注意力机制是一种用于加强深度学习模型对输入数据的空间结构理解的注意力机制。CA 注意力机制的核心思想是引入坐标信息,以便模型可以更好地理解不同位置之间的关系。如下图: 1. 输入特…

【RocketMQ】【源码】Dledger日志复制源码分析

消息存储 在 【RocketMQ】消息的存储一文中提到,Broker收到消息后会调用CommitLog的asyncPutMessage方法写入消息,在DLedger模式下使用的是DLedgerCommitLog,进入asyncPutMessages方法,主要处理逻辑如下: 调用serial…

leetCode 122.买卖股票的最佳时机 II 动态规划 + 状态转移 + 状态压缩

122. 买卖股票的最佳时机 II - 力扣(LeetCode) 给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。 在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买&…

006:连续跌三天,第四天上涨的概率--用python统计

我们已经可以获取到K线信息了,然后我们来进行一些统计,就统计连续三天下跌,第四天上涨的概率。 我们用宁波银行(002142)最近三年的数据来统计。先用上一篇的程序下载到K线数据,得到文件002142.csv。然后在…

Spring修炼之旅(4)静态/动态代理模式与AOP

一、代理模式概述 代理模式 为什么要学习代理模式,因为AOP的底层机制就是动态代理! 代理模式: 静态代理 动态代理 学习aop之前 , 我们要先了解一下代理模式! 1.1静态代理 静态代理角色分析 抽象角色 : 一般使用接口或者抽象…

【数据结构练习】二叉树相关oj题集锦二

目录 前言 1.平衡二叉树 2.对称二叉树 3.二叉树遍历 4.层序遍历 5.判断一棵树是不是完全二叉树 前言 编程想要学的好,刷题少不了,我们不仅要多刷题,还要刷好题!为此我开启了一个弯道超车必做好题锦集的系列,此为…

2023/9/30 使用消息队列完成进程间通信

发送方 ​ #include <myhead.h> //消息结构体 typedef struct {long msgtype; //消息类型char data[1024]; //消息正文 }Msg_ds;#define SIZE sizeof(Msg_ds) - sizeof(long) //正文大小 int main(int argc, const char *argv[]) {//1.创建key值key_t key ;if((key …

中断向量控制器(NVIC)

1. 什么是中断 在处理器中&#xff0c;中断是一个过程&#xff0c;即CPU在正常执行程序的过程中&#xff0c;遇到外部/内部的紧急事件需要处理&#xff0c;暂时中止当前程序的执行&#xff0c;转而去为处理紧急的事件&#xff0c;待处理完毕后再返回被打断的程序处继续往下执行…

Spring MVC 中的国际化和本地化

Spring MVC 中的国际化和本地化 国际化&#xff08;Internationalization&#xff0c;简称i18n&#xff09;和本地化&#xff08;Localization&#xff0c;简称l10n&#xff09;是构建多语言应用程序的重要概念。Spring MVC提供了丰富的支持&#xff0c;使开发人员能够轻松地处…

Python 笔记06(Mysql数据库)

一 基础 1.1 安装 MySQL下载参考&#xff1a;MySQL8.0安装配置教程【超级详细图解】-CSDN博客 测试是否安装并正确配置环境变量&#xff1a; 1.2 查看服务器是否正常运行 1.3 显示数据库 show databases; 1.4 退出 exit 1.5 python 连接 1.6 查主机IP ipconfig

2.springboot代理调用

1.概述 本文介绍在方法上开启声明式事务Transactional后(使用InfrastructureAdvisorAutoProxyCreator创建jdk动态代理)&#xff0c;springboot的调用该方法的过程&#xff1b; 2.结论(重点) 在方法开启声明式事务后&#xff0c;spring会为该对象创建动态代理。spring容器为该…

Android Jetpack组件架构:ViewModel的原理

Android Jetpack组件架构&#xff1a;ViewModel的原理 导言 本篇文章是关于介绍ViewModel的&#xff0c;由于ViewModel的使用还是挺简单的&#xff0c;这里就不再介绍其的基本应用&#xff0c;我们主要来分析ViewModel的原理。 ViewModel的生命周期 众所周知&#xff0c;一般…

聚观早报 | 2024款小鹏P5全新发布;华为发布13.2英寸MatePad Pro

【聚观365】9月26日消息 2024款小鹏P5全新发布 华为发布13.2英寸MatePad Pro 特斯拉发布人形机器人最新进展 百川智能发布Baichuan2-53B 软件行业仍将人才供不应求 2024款小鹏P5全新发布 继2024款小鹏G9问世仅一周&#xff0c;小鹏汽车再度发力新产品&#xff0c;2024款小…

【小沐学前端】Node.js实现UDP通信

文章目录 1、简介2、下载和安装3、代码示例3.1 HTTP3.2 UDP单播3.4 UDP广播 结语 1、简介 Node.js 是一个开源的、跨平台的 JavaScript 运行时环境。 Node.js 是一个开源和跨平台的 JavaScript 运行时环境。 它是几乎任何类型项目的流行工具&#xff01; Node.js 在浏览器之外…

2.4g无线收发芯片:Ci24R1(DFN8)

Ci24R1 采用GFSK/FSK数字调制与解调技术。数据传输速率与PA输出功率都可以调节&#xff0c;支持2Mbps, 1Mbps, 250Kbps三种数据速率。高的数据速率可以在更短的时间完成同样的数据收发&#xff0c;因此可以具有更低的功耗。 Ci24R1 是一颗工作在2.4GHz ISM频段&#xff0c;专为…

医疗实施-住院流程详解

住院就诊流程详解 1.病人入院登记2.病人进入病区3.医生操作病人4.医嘱录入与审核执行5. 医嘱收费前在对应业务系统的操作5.1.药物医嘱5.2.检查检验医嘱5.3.手术医嘱 6.住院医嘱费用的产生7. 医嘱收费后在对应业务系统的操作8. 病人出院 这篇文章是基于我的文章《医疗实施-住院就…

8.3Jmeter使用json提取器提取数组值并循环(循环控制器)遍历使用

Jmeter使用json提取器提取数组值并循环遍历使用 响应返回值例如&#xff1a; {"code":0,"data":{"totalCount":11,"pageSize":100,"totalPage":1,"currPage":1,"list":[{"structuredId":&q…

[React] 性能优化相关

文章目录 1.React.memo2.useMemo3.useCallback4.useTransition5.useDeferredValue 1.React.memo 当父组件被重新渲染的时候&#xff0c;也会触发子组件的重新渲染&#xff0c;这样就多出了无意义的性能开销。如果子组件的状态没有发生变化&#xff0c;则子组件是不需要被重新渲…

百度网盘的扩容

百度网盘的扩容怎么扩 百度网盘的扩容通常需要购买额外的存储空间。以下是扩容百度网盘存储空间的一般步骤&#xff1a; 登录百度网盘&#xff1a;首先&#xff0c;在您的计算机或移动设备上打开百度网盘&#xff0c;并使用您的百度账号登录。 选择扩容选项&#xff1a;一旦登…