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. NX二次开发】Block UI 体收集器

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  2. 彻底解决Spring mvc中时间类型的转换和序列化问题

    在使用Spring mvc 进行开发时我们经常遇到前端传来的某种格式的时间字符串无法用java8时间包下的具体类型参数来直接接收.同时还有一系列的序列化 .反序列化问题,在返回前端带时间类型的同样会出 ...

  3. Nginx为什么快到根本停不下来?

    Nginx 是一个免费的,开源的,高性能的 HTTP 服务器和反向代理,以及 IMAP / POP3 代理服务器. 图片来自 Pexels Nginx 以其高性能,稳定性,丰富的功能,简单的配置和低资 ...

  4. 4.3CNN卷积神经网络最详细最容易理解--tensorflow源码MLP对比

    自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取: https://www.cnblogs.com/bclshuai/p/11380657.html 1.1  CNN卷积神经网络 ...

  5. csp-s模拟测试44「D·E·F」

    用心出题,用脚造数据 乱搞场 1 #include<bits/stdc++.h> 2 #define re register 3 #define int long long 4 #defi ...

  6. OO unit1 summary

    Unit 1 summary 一.前言 三周左右的学习,OO第一单元顺利结束了,个人认为有必要写个blog来反思总结一下自己第一单元的学习情况,以便更好地进行后面的学习. 之前从来没有写blog的习惯 ...

  7. 滑动窗口经典题 leetcode 3. 无重复字符的最长子串

    题目 解题思路 题目要求找出给定字符串中不含有重复字符的最长子串的长度.这是一个典型的滑动窗口的题目,可以通过滑动窗口去解答. 滑动窗口 具体操作如下图示:找到一个子串 s[left...right] ...

  8. MySQL—Dos命令操作数据库

    MySQL 是一个关系型数据库,存在表的概念 结构,数据库可以存放多张表,每个表可以存放多个字段,每个字段可以存放多个记录 Dos命令操作数据库 PhpStudy使用终端打开数据库 第一次打开默认的密 ...

  9. 温故知新Docker概念及Docker Desktop For Windows v3.1.0安装

    Docker 简介 什么是Docker? Docker是一个开放源代码软件项目,项目主要代码在2013年开源于GitHub.它是云服务技术上的一次创新,让应用程序布署在软件容器下的工作可以自动化进行, ...

  10. Visual Studio Code 和Visual Studio插件收集(持续更新)

    Visual Studio Code 插件收集 Chinese (Simplified) Language Pack 默认刚安装的VSC是原味英文的,如果你用不习惯,非常简单,官方出品的简体中文语言包 ...