1.测试框架简介

整个接口测试框架的设计图如下:

base:存放的是请求方法二次封装

common:存放的是自定义工具,操作excel,yaml文件等

data:存放的是公共动态数据,如data.xls/ bookID.md

log:存放的是Log日志信息

report:存放的是接口测试报告

testcase:存放的是接口测试案例

2、重构Requests请求,查看base/method.py文件代码

import requests

class Requests:
# def __init__(self):
# self.s = requests.Session()

def request(self,url,method='get',**kwargs):
if method == 'get':
return requests.Session().request(url=url,method=method,**kwargs)
elif method == 'post':
return requests.Session().request(url=url,method=method,**kwargs)
elif method == 'delete':
return requests.Session().request(url=url,method=method,**kwargs)
elif method == 'put':
return requests.Session().request(url=url,method=method,**kwargs)

def get(self,url,**kwargs):
return self.request(url=url,**kwargs)

def post(self,url,**kwargs):
return self.request(url=url,method='post',**kwargs)

def delete(self,url,**kwargs):
return self.request(url=url,method='delete',**kwargs)

def put(self,url,**kwargs):
return self.request(url=url,method='put',**kwargs)

3、重构公共工具类方法,参考common/helper.py文件代码
import os
import logging
import datetime

def FilePath(filePath=None,fileName=None):
"""文件的路径封装"""
return os.path.join(os.path.dirname(os.path.dirname(__file__)),filePath,fileName)

def writeBookID(content):
"""写入BookID -->取出的ID为整型需强制转换为str类型"""
# print("文件写入的时间:",datetime.datetime.now())
with open(FilePath(filePath='data',fileName='bookID.md'),'w') as fp:
fp.write(str(content))

def readBookID():
"""读取BookID"""
# print("文件读取时间:",datetime.datetime.now())
with open(FilePath(filePath='data',fileName='bookID.md')) as fp:
return fp.read()

def log(log_content):
'''日志定义级别'''
# 定义文件
logFile = logging.FileHandler(FilePath('log','logInfo.md'), 'a',encoding='utf-8')
# log格式
fmt = logging.Formatter(fmt='%(asctime)s-%(name)s-%(levelname)s-%(module)s:%(message)s')
logFile.setFormatter(fmt)

# 定义日志
logger1 = logging.Logger('logTest', level=logging.DEBUG)
logger1.addHandler(logFile)
logger1.info(log_content)
logFile.close()

参考common/OperaExcel.py 文件:
import xlrd
from TestCase.ApiLogin_Po.common.OperaYaml import OperaYaml
from TestCase.ApiLogin_Po.common.helper import *

class ExcelValues:
"""Excel表的列固定"""
CaseID = 0
Desc = 1
Url = 2
Data = 3
Method = 4
Expect = 5

@property
def GetCaseID(self):
"""返回CaseID列"""
return self.CaseID

@property
def GetDesc(self):
"""返回Desc列"""
return self.Desc

@property
def GetUrl(self):
"""返回Url列"""
return self.Url

@property
def GetData(self):
"""返回Data列"""
return self.Data

@property
def GetMethod(self):
"""返回Method列"""
return self.Method

@property
def GetExpect(self):
"""返回Expect列"""
return self.Expect

class OperationExcel(OperaYaml):

@property
def readExcel(self):
"""获取Books工作表"""
sheets = xlrd.open_workbook(FilePath(filePath='data',fileName='data1.xlsx'))
return sheets.sheet_by_index(0)

def readValues(self,rowx,colx):
"""获取工作表的行、列"""
return self.readExcel.cell_value(rowx=rowx,colx=colx)

def readCaseID(self,rowx):
"""获取工作表接口ID"""
return self.readValues(rowx,ExcelValues().GetCaseID)

def readDesc(self,rowx):
"""获取工作表接口描述"""
return self.readValues(rowx,ExcelValues().GetDesc)

def readUrl(self,rowx):
"""获取工作表接口URL"""
url = self.readValues(rowx,ExcelValues().GetUrl)
if '{bookid}' in url:
return str(url).replace('{bookid}',readBookID())
else:
return url

def readData(self,rowx):
"""获取工作表接口Data"""
return self.readValues(rowx,ExcelValues().GetData)

def readMethod(self,rowx):
"""获取工作表接口方法"""
return self.readValues(rowx,ExcelValues().GetMethod)

def readExpect(self,rowx):
"""获取工作表接口预期结果"""
return self.readValues(rowx,ExcelValues().GetExpect)

def readJsonValues(self,rowx):
"""获取book.yaml文件的data值,readData对应是yaml文件的book_002,004"""
return self.readBookYaml()[self.readData(rowx)]

if __name__ == '__main__':
obj = OperationExcel()
# print(obj.readValues(1,ExcelValues().GetExpect))
# print(obj.readExpect(4),type(obj.readExpect(4)))

参考common/OperaYaml.py文件
from TestCase.ApiLogin_Po.common.helper import *
import yaml

class OperaYaml:

def readYaml(self):
with open(FilePath('data','data.yaml'),encoding='utf-8') as fp:
return list(yaml.safe_load_all(fp))

def readBookYaml(self):
with open(FilePath(filePath='data',fileName='book.yaml'),encoding='utf-8') as fp:
return yaml.safe_load(fp)

if __name__ == '__main__':
obj = OperaYaml()
# print(type(obj.readBookYaml()['book_002']))
# for item in obj.readYaml():
# print(item)

4、参考data/book.yaml文件

参考data/data1.xlsx文件

5、参考test_authFlask.py 文件,启动flask服务

from flask import Flask, jsonify, make_response, abort, Response, request
from flask_restful import Api, Resource, reqparse
from flask_httpauth import HTTPBasicAuth

app = Flask(__name__)
api = Api(app=app)
auth = HTTPBasicAuth()

# 认证通过
@auth.get_password
def get_password(username):
if username == "Admin":
return "admin"

# 认证不通过的错误信息
@auth.error_handler
def authrized():
return make_response(jsonify({'msg': '您好,请认证'}), 401)

@app.errorhandler(404)
def not_found(error):
return make_response(jsonify({"error": "请求页面不存在!"}), 404)

@app.errorhandler(405)
def not_found(error):
return make_response(jsonify({"error": "请求方式不对!"}), 405)

books = [
{'ID': 1, 'author': 'Teacher', 'name': 'Python', 'done': True},
{'ID': 2, 'author': 'Teacher', 'name': 'Selenium', 'done': True},
{'ID': 3, 'author': 'Teacher', 'name': 'Appium', 'done': False},
]

class Books(Resource):
# 鉴权认证(登录)
decorators = [auth.login_required]

# 查看全部书籍
def get(self):
return jsonify({'data': books})

# 添加部分书籍
def post(self):
if not Response.json:
abort(404)
else:
book = {
'ID': books[-1]['ID'] + 1,
'author': request.json.get('author'),
'name': request.json.get('name'),
'done': False
}
books.append(book)
return jsonify({'status': 1001, 'msg': '添加书籍成功', 'data': book})

class Book(Resource):
# 鉴权认证(登录)
decorators = [auth.login_required]

# 根据ID查询对应书籍
def get(self, book_id):
book = list(filter(lambda t: t['ID'] == book_id, books))
if len(book) == 0:
abort(404)

else:
return jsonify({'status': 1002, 'msg': 'ok', 'data': book})

# 根据ID删除对应书籍
def delete(self, book_id):
book = list(filter(lambda t: t['ID'] == book_id, books))
if len(book) == 0:
abort(404)
else:
books.remove(book[0])
return jsonify({'status': 1003, 'msg': '删除书籍成功', 'data': book})

# 根据ID更新对应书籍
def put(self, book_id):
book = list(filter(lambda t: t['ID'] == book_id, books))
if len(book) == 0:
abort(404)

elif not Response.json:
abort(404)

elif 'author' not in request.json and 'name' not in request.json:
abort(404)

elif 'done' not in request.json and type(request.json['done'] is not bool):
abort(404)

else:
book[-1]['author'] = request.json.get('author', book[-1]['author'])
book[-1]['name'] = request.json.get('name', book[-1]['name'])
book[-1]['done'] = request.json.get('done', book[-1]['done'])
return jsonify({'status': 1004, 'msg': '更新书籍成功', 'data': book})

api.add_resource(Books, '/v1/api/books')
api.add_resource(Book, '/v1/api/book/<int:book_id>')

if __name__ == "__main__":
app.run(debug=True,port=5555)
6、结合pytest框架编写测试用例
import pytest
import json
from TestCase.ApiLogin_Po.base.method import Requests
from TestCase.ApiLogin_Po.common.OperaExcel import OperationExcel
from TestCase.ApiLogin_Po.common.helper import *
from requests.auth import HTTPBasicAuth

class TestBooks:
excel = OperationExcel()
obj = Requests()
auth = HTTPBasicAuth('Admin','admin')

def test_book_001(self):
"""查询所有书籍信息"""
r = self.obj.get(url=self.excel.readUrl(1),auth=self.auth)
assert self.excel.readExpect(1) in json.dumps(r.json()['data'][0]['author'])
assert r.status_code == 200
log("查询所有书籍成功")
# print(r.json()['data'],type(r.json()['data']))
# for item in r.json()['data']:
# print(item)

def test_book_002(self):
"""添加书籍请求"""
r = self.obj.post(
url=self.excel.readUrl(2),
json=self.excel.readJsonValues(2),
auth=self.auth
)
writeBookID(r.json()['data']['ID'])
assert self.excel.readExpect(2) in json.dumps(r.json()['msg'],ensure_ascii=False)
assert r.status_code == 200
log("添加书籍成功")
# print(json.dumps(r.json(),ensure_ascii=False))

def test_book_003(self):
"""查看已添加的书籍"""
r = self.obj.get(
url=self.excel.readUrl(3),
auth=self.auth
)
# print(type(r.json()['status']))
assert self.excel.readExpect(3) == float(r.json()["status"])
assert r.status_code == 200
log("查看已添加书籍成功")

def test_book_004(self):
"""更新/修改已添加的书籍"""
r = self.obj.put(
url=self.excel.readUrl(4),
json=self.excel.readJsonValues(4),
auth=self.auth
)
# print(type(json.dumps(r.json()['msg'],ensure_ascii=False)))
assert self.excel.readExpect(4) in json.dumps(r.json()['msg'],ensure_ascii=False)
assert r.status_code == 200
log("更新/修改已添加的书籍成功")

def test_book_005(self):
"""删除已编辑的书籍"""
r = self.obj.delete(
url=self.excel.readUrl(5),
auth=self.auth
)
# print(r.json())
assert self.excel.readExpect(5) in json.dumps(r.json()['msg'], ensure_ascii=False)
assert r.status_code == 200
log("删除已编辑的书籍成功")

if __name__ == '__main__':
# BB = Book()
# print(BB.excel.readUrl(1))
# pytest.main(["-s", "-v", "test_Books.py"])
pytest.main(["-s","-v","test_Books.py","--alluredir","./report/result"])
import subprocess
subprocess.call('allure generate report/result/ -o report/html --clean',shell=True)
subprocess.call('allure open -h 127.0.0.1 -p 8088 ./report/html',shell=True)

7、打开allure框架的测试报告
前提需:allure-2.7.0添加到path,安装pip install allure-pytest

Python+API接口测试框架设计(pytest)的更多相关文章

  1. python+API接口测试框架设计(unittest)

    1.测试框架简介 整个接口测试框架的设计图如下: basepage:存放的是公共的方法 common:存放的是自定义工具 data:存放的是公共动态数据,如BB.xls/ Id.md log:存放的是 ...

  2. 基于python的接口测试框架设计(三)接口测试的框架

    基于python的接口测试框架设计(三)接口测试的框架 其实我这里用到的是unittest单元测试框架,,这个框架好就好在比较清楚,,setup terdown都可以处理一些初始化及完成后的工作 主要 ...

  3. 基于python的接口测试框架设计(二)配置一些参数及文件

    基于python的接口测试框架设计(二)配置一些参数及文件 我这里需要基于我的项目配置的主要是登陆参数.以及baseURL ,把这些放在单独的文件里  毕竟导入的时候方便了一些 首先是url 图略 建 ...

  4. 基于python的接口测试框架设计(一)连接数据库

    基于python的接口测试框架设计(一)连接数据库 首先是连接数据库的操作,最好是单独写在一个模块里, 然后便于方便的调用,基于把connection连接放在__init__()方法里 然后分别定义D ...

  5. 【转】基于Python的接口测试框架实例

    下面小编就为大家带来一篇基于Python的接口测试框架实例.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧   背景 最近公司在做消息推送,那么自然就会产生很多接口,测试 ...

  6. 基于Python的接口测试框架实例

    文章来源:http://www.jb51.net/article/96481.htm 下面小编就为大家带来一篇基于Python的接口测试框架实例.小编觉得挺不错的,现在就分享给大家,也给大家做个参考. ...

  7. python+selenium之框架设计

    一.自动化测试框架 1.什么是自动化测试框架 简单来说,自动化测试框架就是由一些标准,协议,规则组成,提供脚本运行的环境.自动化测试框架能够提供很多便利给用户高效完成一些事情,例如,结构清晰开发脚本, ...

  8. 基于Python的接口测试框架

    分析 接口是基于HTTP协议的,那么说白了,就是发起HTTP请求就行了,对于Python来说比较简单.直接使用requests就可以很轻松的完成任务. 架构 整个框架是比较小的,涉及的东西也比较少,只 ...

  9. [转]基于Python的接口测试框架

    http://blog.csdn.net/wyb199026/article/details/51485322 背景 最近公司在做消息推送,那么自然就会产生很多接口,测试的过程中需要调用接口,我就突然 ...

随机推荐

  1. C ++变量,文字和常量

    C ++变量,文字和常量 本文将借助示例来学习C ++中的变量,文字和常量. C ++变量 在编程中,变量是用于保存数据的容器(存储区). 为了指示存储区域,应该为每个变量赋予唯一的名称(标识符).例 ...

  2. 一、部署监控服务器--安装LNMP环境

    1.要求: 本案例要求部署-台Zabbix监控服务器, -台被监控主机,为进一步执行具体的监控任务做准备:1.安装LNMP环境2.源码安装Zabbix3.安装监控端主机,修改基本配置4.初始化Zabb ...

  3. 一、DNS服务器的搭建

    一.介绍 DNS服务:域名解析   将域名解析ip地址 DNS服务器的功能– 正向解析:根据注册的域名查找其对应的IP地址– 反向解析:根据IP地址查找对应的注册域名,不常用 所有完整的域名都要以点结 ...

  4. JSON.parse无双引号如何实现转换

    用JSON.parse()做转换,必须用双引号包起来.但是我用chrome的devtools时,它可以自动转换.于是上网查了一下,原来可以通过replace方法格式化一下.(修改后可以兼容日期格式) ...

  5. java笔试题(二)

    1.写出一维数组初始化的两种方式 int[] arr={1,2,3}; String[] str=new String[2]; str[1]="23"; 2.写出二维数组初始化的两 ...

  6. Docker(39)- docker 实战二之安装 Tomcat

    背景 参考了狂神老师的 Docker 教程,非常棒! https://www.bilibili.com/video/BV1og4y1q7M4?p=15 直接运行容器 本地找不到镜像会自动下载 --rm ...

  7. 痞子衡嵌入式:在串口波特率识别实例里逐步展示i.MXRT上提升代码执行性能的十八般武艺

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是在串口波特率识别实例里逐步展示i.MXRT上提升代码执行性能的十八般武艺. 恩智浦 MCU SE 团队近期一直在加班加点赶 SBL 项目 ...

  8. 14.5、redis-sentinel高可用

    1.redis主从同步配置: (0)主机配置: 服务器名称 ip地址 实例6379 实例6380 实例6381 controller-node1 172.16.1.90 主 从 从 (1)确定主从: ...

  9. API安全综述

    API安全综述 译自:An Overview on API Security. 本文概括了API防护有关的方方面面,从上层视角介绍了API防护中主要注意的点,并给出了相应的建议.本文可以作为一个API ...

  10. 从DVWA靶场学代码审计

    DVWA是较为经典的一个传统漏洞的靶场 内置了low,medium,hight,impossible四个安全级别供安全人员去研究相关漏洞.今天就来对impossible这个级别进行代码审计,从中学习一 ...