前言:目前公司的主要产品是一个web类型的产品;需要做一些自动化,目前的想法是只做接口自动化,不做ui的一个自动化,目前的思路是先对主流程做正常校验,后期再对每一个接口做校验;

  一、版本信息:

    python版本:3.8.6

    其他用:pip install -r requirements.txt

    requirements.txt

allure-pytest==2.8.18
allure-python-commons==2.8.18
atomicwrites==1.4.0
attrs==20.2.0
certifi==2020.6.20
cffi==1.14.2
chardet==3.0.4
colorama==0.4.3
configobj==5.0.6
configparser==5.0.0
cryptography==3.1
enum34==1.1.10
ffmpy==0.2.3
gevent==20.9.0
greenlet==0.4.17
idna==2.10
importlib-metadata==1.7.0
iniconfig==1.0.1
lxml==4.5.2
more-itertools==8.5.0
namedlist==1.8
packaging==20.4
pluggy==0.13.1
py==1.9.0
pycparser==2.20
pyOpenSSL==19.1.0
pyparsing==2.4.7
pytest==6.0.2
pytest-html==2.1.1
pytest-metadata==1.10.0
pytest-ordering==0.6
pytest-pythonpath==0.7.3
pytils==0.3
PyYAML==5.3.1
requests==2.24.0
selenium==3.141.0
six==1.15.0
toml==0.10.1
tools==0.1.9
urllib3==1.25.10
zipp==3.1.0
zope.event==4.5.0
zope.interface==5.2.0

 

  二、项目结构:

    

    具体模块介绍:

Common:基础方法文件夹
assert.py:重写assert方法
commonMethod.py:存一些常用方法,目前存了循环拿key为xx的value值
conf.py:读写conf配置方法
consts.py:计划用来存放全局变量,目前也用不上,可用来运行调试代码
emailSend.py:发送邮件方法
log.py:生成日志方法
multitasks.py:多任务方法,目前还没写
request.py:请求方法
yamls.py:读写yaml文件方法
Conf:存放配置
conf.ini: 存放配置内容;
Data:存放程序中需要用到的文件;
Log:存放日志
Params:存放测试用例,以yaml形式存储,按模块新建文件夹,存放用例
Report:存放allure数据及报告
allure-reports:存放allure数据
html:allure数据解析成html文件
Testcase:测试方法,以模块来定义py文件及文件名
gitignore:上传git时忽略哪些文件
conftest.py:pytest框架默认文件,可存放fixture配置文件
requirements.txt: 项目中所用的依赖包;
run.py:启动文件

   

  三、公共模块代码;

    assert.py

# 重写assert方法
from Common.log import logger class Assert:
def assertEquals(self, actual, expected):
"""
:param actual:实际值
:param expected: 期望值
:return:
"""
try:
assert str(actual) == str(expected)
logger.info("断言成功,实际值:{} 等于预期值{}".format(actual, expected))
except AssertionError as e:
logger.error("断言失败,实际值:{}不等于预期值:{}".format(actual, expected))
raise e def assertTrue(self, actual):
'''
:param actual: 实际值
:return:
'''
try:
assert actual == True
logger.info("断言成功,实际值:{}为真".format(actual))
except AssertionError as e:
logger.error("断言失败,实际值:{}不为真".format(actual))
raise e def assertIn(self, content, target): try:
assert content in target
logger.info("断言成功,目标文本:{}包含文本:{}".format(target, content))
except AssertionError as e:
logger.error("断言失败,目标文本:{}不包含文本:{}".format(target, content))

    commonMethod.py

# 循环拿key为objkey的value值
def get_value(data, objkey, store_data):
if isinstance(data, dict):
for k, v in data.items():
if k == objkey and v:
store_data.append(v)
else:
if isinstance(v, dict) or isinstance(v, list):
get_value(v, objkey, store_data)
elif isinstance(data, list):
for i in data:
if isinstance(data, dict) or isinstance(data, list):
get_value(i, objkey, store_data)
return store_data

    conf.py

# -*- coding: utf-8 -*-
# @Time : 2020/6/3 15:48
# @Author : Jackyuan
# @File : conf.py from configobj import ConfigObj
import os class Config:
curpath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
cfgpath = os.path.join(curpath, "./Conf/conf.ini")
confObj = ConfigObj(cfgpath, encoding='utf-8') @classmethod
def config(self, section):
return self.confObj[section] @classmethod
def setToken(self, value):
self.confObj['TOKEN']['token'] = value
self.confObj.write() @classmethod
def setMyInfo(self, value):
self.confObj['MYINFO']['myinfo'] = value
self.confObj.write() if __name__ == '__main__':
print(Config.config("ENV"))

    emailSend.py

# 封装发送邮件方法
import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.mime.multipart import MIMEMultipart
from Common.conf import Config
from Common.log import logger email_conf = Config.config("EMAIL") class SendEmail(object):
def __init__(self):
# 连接smtp服务器
self.smtpObj = smtplib.SMTP_SSL(email_conf['mail_host'], email_conf['port'])
# 登录smtp服务器
self.smtpObj.login(email_conf['mail_user'], email_conf['mail_pwd']) # 构建不带附件的邮件正文
def content_email(self, content):
# 构建文件正文
message = MIMEText(content, 'plain', 'utf-8')
# 添加发件人
message['From'] = Header(email_conf["sender"], 'utf-8')
# 添加收件人
message['To'] = Header(",".join(email_conf["receivers"]), "utf-8")
# 添加邮件主题
message['subject'] = Header(email_conf["subject"], 'utf-8')
# 发送邮件
self.send_email(message) # 构建带附件的邮件
def attr_email(self, content, file_url):
message = MIMEMultipart()
# 添加发件人
message['From'] = Header(email_conf["sender"], 'utf-8')
# 添加收件人
message['To'] = Header(",".join(email_conf["receivers"]), "utf-8")
# 添加邮件主题
message['subject'] = Header(email_conf["subject"], 'utf-8')
# 创建邮件正文及附件
message.attach(MIMEText(content, "plain", "utf-8"))
# 构造附件1
att1 = MIMEText(open(file_url, 'rb').read(), 'html', 'utf-8')
att1["Content-Type"] = 'application/octet-stream'
# 这里的filename可以任意写,写什么名字,邮件中显示什么名字
att1["Content-Disposition"] = 'attachment; filename="test.html"'
message.attach(att1)
# 发送邮件
self.send_email(message) # 发送邮件
def send_email(self, message):
try:
self.smtpObj.sendmail(email_conf["sender"], email_conf["receivers"], message.as_string())
except Exception as e:
logger.error("发送带附件的邮件失败:{}".format(e))

    log.py

# 日志收集设置
import logging, os
from logging.handlers import TimedRotatingFileHandler
import datetime current_dir = os.path.abspath(os.path.dirname(__file__))
parent_dir = os.path.dirname(current_dir)
my_log_path = os.path.join(parent_dir, "./Log")
if not os.path.exists(my_log_path):
os.mkdir(my_log_path)
my_report_path = os.path.join(parent_dir, "./Report")
if not os.path.exists(my_report_path):
os.mkdir(my_report_path) # 定义一个日志收集器
logger = logging.getLogger("guoguo")
# 设置收集器级别,不设定的话,会默认搜集warning及以上级别的日志
logger.setLevel(logging.INFO)
# 设置日志格式
fmt = logging.Formatter("%(filename)s-%(lineno)d-%(asctime)s-%(levelname)s-%(message)s") # 设置日志输出到控制台
stream_handler = logging.StreamHandler()
# 设置日志输出到文件
file_handler = TimedRotatingFileHandler('Log/{}.log'.format(datetime.datetime.now().strftime('%Y-%m-%d')), when="D", interval=1, backupCount=30, encoding='utf-8') # 设置控制台和文件的日志输出格式
stream_handler.setFormatter(fmt)
file_handler.setFormatter(fmt) # 将输出对象添加到logger中
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
"""
收集日志
logger.info()
logger.debug()
logger.warning()
logger.error()
"""

    requests.py

# 封装请求方法
import requests
from Common.log import logger
from Common.conf import Config # 获取配置文件中的token
token = {"token": Config.config("TOKEN")['token']} class RequestMethod(object):
# 请求日志
def api_log(self, method, url, headers=None, params=None, data=None, files=None, code=None, res_header=None, res_text=None, time=None):
logger.info("请求方式===>{}".format(method))
logger.info("请求路径===>{}".format(url))
logger.info("请求头===>{}".format(headers))
logger.info("请求参数===>{}".format(params))
logger.info("请求体===>{}".format(data))
logger.info("上传的文件内容===>{}".format(files))
logger.info("响应状态码===>{}".format(code))
logger.info("响应头===>{}".format(res_header))
logger.info("响应体===>{}".format(res_text.decode("utf-8")))
logger.info("响应时间===>{}".format(time)) # get请求
def get_main(self, url, headers, params=None):
try:
response = requests.get(url=url, headers=headers, params=params)
return response
except Exception as e:
logger.error("{}该路径get请求出错,错误原因{}".format(url, e)) # post请求
def post_main(self, url, headers, params=None, data=None, files=None):
try:
response = requests.post(url=url, headers=headers, params=params, data=data, files=files)
return response
except Exception as e:
logger.error("{}该路径post请求出错,错误原因:{}".format(url, e)) # put请求
def put_main(self, url, headers, params=None, data=None, files=None):
try:
response = requests.put(url=url, headers=headers, params=params, data=data, files=files)
return response
except Exception as e:
logger.error("{}该路径put请求出错,错误原因{}".format(url, e)) # delete请求
def delete_main(self, url, headers, params=None):
try:
response = requests.delete(url=url, headers=headers, params=params)
return response
except Exception as e:
logger.error("{}该路径delete请求出错,错误原因{}".format(url, e)) # 选择调用方法
def run_main(self, method, url, headers=None, data=None, params=None, files=None):
if headers is None:
headers = token
else:
headers.update(token)
if method == "get":
response = self.get_main(url, headers, params=params)
elif method == "post":
response = self.post_main(url, headers, params=params, data=data, files=files)
elif method == "put":
response = self.put_main(url, headers, params=params, data=data, files=files)
elif method == "delete":
response = self.delete_main(url, headers, params=params)
else:
logger.error("请求方式有误")
self.api_log(method=method, url=response.url, headers=headers, params=params, data=data, files=None, code=response.status_code, res_header=response.headers, res_text=response.content, time=response.elapsed.total_seconds())
return response

    yamls.py

import yaml
from Common.log import logger class ReadYaml(object):
def __init__(self, file_url, write_data=None):
self.file_url = file_url
self.write_data = write_data # 读取yaml数据
def read_yaml(self):
file_data = None
try:
with open(self.file_url, "r", encoding='utf-8') as f:
file_data = yaml.safe_load(f.read())
logger.info("读取{}数据成功,读取数据为:\n{}".format(self.file_url, file_data))
except Exception as e:
logger.error("{}读取失败,失败原因为:{}".format(self.file_url, e))
return file_data # 向yaml写入数据
def write_yaml(self, method):
if method == "append":
method = "a+"
elif method == "write":
method = 'w+'
else:
return "method錯誤"
try:
with open(self.file_url, method, encoding="utf-8") as f:
yaml.dump(self.write_data, f)
logger.info("写入数据成功,写入后数据为:\n{}".format(self.file_url, self.read_yaml()))
except Exception as e:
logger.error("{}写入数据失败,失败原因为:{}".format(self.file_url, e))
return self.read_yaml()

  

pytest接口自动化搭建经验的更多相关文章

  1. Pytest(18)pytest接口自动化完整框架思维导图

    pytest接口自动化完整框架思维导图

  2. python+pytest接口自动化(11)-测试函数、测试类/测试方法的封装

    前言 在python+pytest 接口自动化系列中,我们之前的文章基本都没有将代码进行封装,但实际编写自动化测试脚本中,我们都需要将测试代码进行封装,才能被测试框架识别执行. 例如单个接口的请求代码 ...

  3. python+pytest接口自动化(12)-自动化用例编写思路 (使用pytest编写一个测试脚本)

    经过之前的学习铺垫,我们尝试着利用pytest框架编写一条接口自动化测试用例,来厘清接口自动化用例编写的思路. 我们在百度搜索天气查询,会出现如下图所示结果: 接下来,我们以该天气查询接口为例,编写接 ...

  4. python+pytest接口自动化(13)-token关联登录

    在PC端登录公司的后台管理系统或在手机上登录某个APP时,经常会发现登录成功后,返回参数中会包含token,它的值为一段较长的字符串,而后续去请求的请求头中都需要带上这个token作为参数,否则就提示 ...

  5. python+pytest接口自动化(16)-接口自动化项目中日志的使用 (使用loguru模块)

    通过上篇文章日志管理模块loguru简介,我们已经知道了loguru日志记录模块的简单使用.在自动化测试项目中,一般都需要通过记录日志的方式来确定项目运行的状态及结果,以方便定位问题. 这篇文章我们使 ...

  6. python+pytest接口自动化

    本篇文章是用python+pytest写了一个简单的接口自动化脚本,外加循环请求接口的语法,大家可以参考~ 实例一: import requestsimport pytestimport time c ...

  7. python+pytest接口自动化(4)-requests发送get请求

    python中用于请求http接口的有自带的urllib和第三方库requests,但 urllib 写法稍微有点繁琐,所以在进行接口自动化测试过程中,一般使用更为简洁且功能强大的 requests ...

  8. python+pytest接口自动化(6)-请求参数格式的确定

    我们在做接口测试之前,先需要根据接口文档或抓包接口数据,搞清楚被测接口的详细内容,其中就包含请求参数的编码格式,从而使用对应的参数格式发送请求.例如某个接口规定的请求主体的编码方式为 applicat ...

  9. python+pytest接口自动化(9)-cookie绕过登录(保持登录状态)

    在编写接口自动化测试用例或其他脚本的过程中,经常会遇到需要绕过用户名/密码或验证码登录,去请求接口的情况,一是因为有时验证码会比较复杂,比如有些图形验证码,难以通过接口的方式去处理:再者,每次请求接口 ...

  10. python pytest接口自动化框架搭建(一)

    1.首先安装pytest pip install pytest 2.编写单测用例 在pytest框架中,有如下约束: 所有的单测文件名都需要满足test_*.py格式或*_test.py格式. 在单测 ...

随机推荐

  1. 手把手带你认识GaussDB轻量化运维管理工具

    本文分享自华为云社区<GaussDB轻量化运维管理工具介绍>,作者: Gauss松鼠会小助手. 一.GaussDB 运维管理平台简介 开放生态层 友好Web界面,多云皮肤个性化定制 丰富的 ...

  2. Python 潮流周刊第 41 期(摘要),赠书5本

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  3. vite环境配置mockjs

    mockjs使用文档v2.9.6 安装插件 npm i mockjs -S npm i vite-plugin-mock@2.9.6 配置vite.config.ts文件 export default ...

  4. 逆向通达信Level-2 续七 (调试内置WebView)

    通过窗口找WebView,打开DevTool调试 在WebView hack入控制台.那个,我已经打开了DevTool,算了. 通过pad面板找WebView. 逆向通达信Level-2 续十一 (无 ...

  5. 安装YCM

    安装Vundle git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim Vundle也是vim的 ...

  6. 00-【K210】API资料、电气接线图、PCB文件

    K210的接口说明文档 API接口文档: 链接:https://pan.baidu.com/s/1mlzYRJYQIeHSEMysp_v4cg?pwd=pjmv 提取码:pjmv 2.原理图.PCB文 ...

  7. Linux输入输出

    1.重定向概述 1.什么是重定向 将原本要输出到屏幕的数据信息,重新定向到某个指定的文件中.比如:每天凌晨定时备份数据,希望将备份数据的结果保存到某个文件中. 这样第二天通过查看文件的内容就知道昨天备 ...

  8. C++ memcpy、memmove

    函数原型: void *memcpy(void *dest, const void* src, size_t count ); void *memmove(void *dest, const void ...

  9. quantus18的signaltap逻辑分析仪

    SignalTap的使用 1.SignalTap的作用 SignalTap就是一个IP(对应xilinx的ila),可以将引脚的状态实时显示.这是基于板级的验证,可以有效处理一些仿真难以实现的波形测试 ...

  10. 【Pavia】遥感图像数据集下载地址和读取数据集代码

    [Pavia]遥感图像数据集下载地址和读取数据集代码 目录 [Pavia]遥感图像数据集下载地址和读取数据集代码 前言 Pavia数据集 Pavia数据集地址: Pavia数据集预览 PaviaU.m ...