第一部分: 項目介紹及框架規(guī)劃
接口測試框架流程
接口測試代碼結(jié)構(gòu)
第二部分:接口自動化框架編寫
1. Requests 的封裝
import requests
from utils.LogUtil import my_log
#1而柑、創(chuàng)建封裝get方法
def requests_get(url,headers):
#2司致、發(fā)送requests get請求
r = requests.get(url,headers = headers)
#3见咒、獲取結(jié)果相應(yīng)內(nèi)容
code = r.status_code
try:
body = r.json()
except Exception as e:
body = r.text
#4姜性、內(nèi)容存到字典
res = dict()
res["code"] = code
res["body"] = body
#5杏慰、字典返回
return res
#post方法封裝
#1、創(chuàng)建post方法
def requests_post(url,json=None,headers=None):
#2攘须、發(fā)送post請求
r= requests.post(url,json=json,headers=headers)
#3灰蛙、獲取結(jié)果內(nèi)容
code = r.status_code
try:
body = r.json()
except Exception as e:
body = r.text
#4、內(nèi)容存到字典
res = dict()
res["code"] = code
res["body"] = body
#5限次、字典返回
return res
#重構(gòu)
#1芒涡、創(chuàng)建類
class Request:
#2、定義公共方法
def __init__(self):
self.log = my_log("Requests")
def requests_api(self,url,data = None,json=None,headers=None,cookies=None,method="get"):
if method =="get":
#get請求
self.log.debug("發(fā)送get請求")
r = requests.get(url, data = data, json=json, headers=headers,cookies=cookies)
elif method == "post":
#post請求
self.log.debug("發(fā)送post請求")
r = requests.post(url,data = data, json=json, headers=headers,cookies=cookies)
#2. 重復(fù)的內(nèi)容卖漫,復(fù)制進來
#獲取結(jié)果內(nèi)容
code = r.status_code
try:
body = r.json()
except Exception as e:
body = r.text
#內(nèi)容存到字典
res = dict()
res["code"] = code
res["body"] = body
#字典返回
return res
#3费尽、重構(gòu)get/post方法
#get
#1、定義方法
def get(self,url,**kwargs):
#2羊始、定義參數(shù)
#url,json,headers,cookies,method
#3旱幼、調(diào)用公共方法
return self.requests_api(url,method="get",**kwargs)
def post(self,url,**kwargs):
#2、定義參數(shù)
#url,json,headers,cookies,method
#3突委、調(diào)用公共方法
return self.requests_api(url,method="post",**kwargs)
2.Yaml 文件的封裝
import os
import yaml
#1柏卤、創(chuàng)建類
class YamlReader:
#2、初始化匀油,文件是否存在
def __init__(self,yamlf):
if os.path.exists(yamlf):
self.yamlf = yamlf
else:
raise FileNotFoundError("文件不存在")
self._data = None
self._data_all = None
#3缘缚、yaml讀取
#單個文檔讀取
def data(self):
#第一次調(diào)用data,讀取yaml文檔敌蚜,如果不是桥滨,直接返回之前保存的數(shù)據(jù)
if not self._data:
with open(self.yamlf,"rb") as f:
self._data = yaml.safe_load(f)
return self._data
#多個文檔讀取
def data_all(self):
#第一次調(diào)用data,讀取yaml文檔,如果不是齐媒,直接返回之前保存的數(shù)據(jù)
if not self._data_all:
with open(self.yamlf,"rb") as f:
self._data_all = list(yaml.safe_load_all(f))
return self._data_all
3.日志文件的封裝
import logging
from config import Conf
import datetime,os
from config.Conf import ConfigYaml
#定義日志級別的映射
log_l = {
"info": logging.INFO,
"debug": logging.DEBUG,
"warning": logging.WARNING,
"error": logging.ERROR
}
#1酸舍、創(chuàng)建類
class Logger:
#2、定義參數(shù)
#輸出文件名稱里初,Loggername啃勉,日志級別
def __init__(self,log_file,log_name,log_level):
self.log_file = log_file #擴展名 配置文件
self.log_name = log_name #參數(shù)
self.log_level = log_level # 配置文件
#3、編寫輸出控制臺或文件
# 設(shè)置logger名稱
self.logger = logging.getLogger(self.log_name)
# 設(shè)置log級別
self.logger.setLevel(log_l[self.log_level]) #logging.INFO
#判斷handlers是否存在
if not self.logger.handlers:
# 輸出控制臺
fh_stream = logging.StreamHandler()
fh_stream.setLevel(log_l[self.log_level])
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s ')
fh_stream.setFormatter(formatter)
# 寫入文件
fh_file = logging.FileHandler(self.log_file)
fh_file.setLevel(log_l[self.log_level])
fh_file.setFormatter(formatter)
# 添加handler
self.logger.addHandler(fh_stream)
self.logger.addHandler(fh_file)
#1双妨、初始化參數(shù)數(shù)據(jù)
#日志文件名稱淮阐,日志文件級別
#日志文件名稱 = logs目錄 + 當(dāng)前時間+擴展名
#log目錄
log_path = Conf.get_log_path()
#當(dāng)前時間
current_time = datetime.datetime.now().strftime("%Y-%m-%d")
#擴展名
log_extension = ConfigYaml().get_conf_log_extension()
logfile = os.path.join(log_path,current_time+log_extension)
#print(logfile)
#日志文件級別
loglevel = ConfigYaml().get_conf_log()
#print(loglevel)
#2、對外方法刁品,初始log工具類泣特,提供其它類使用
def my_log(log_name = __file__):
return Logger(log_file=logfile,log_name=log_name,log_level=loglevel).logger
if __name__ == "__main__":
my_log().debug("this is a debug")
4.pytest的應(yīng)用
之前總結(jié)的文檔: http://www.reibang.com/p/981c32b65de1
[pytest]
# 命令行參數(shù)----空格分隔,可添加多個命令行參數(shù) -所有參數(shù)均為插件包的參數(shù)
addopts = -s -reruns 1 --html=../report/report.html
# 測試路徑----當(dāng)前目錄下的scripts文件夾 -可自定義
testpaths = ../scripts
# 搜索文件名----當(dāng)前目錄下的scripts文件夾下挑随,以test_開頭状您,以.py結(jié)尾的所有文件 -可自定義
python_files = test_*.py
# 搜索測試類名----當(dāng)前目錄下的scripts文件夾下,以Test_開頭的類 -可自定義
python_classes = Test_*
# 搜索測試方法名----當(dāng)前目錄下的scripts文件夾下兜挨,以Test_開頭的類內(nèi)膏孟,以test_開頭的方法 -可自定義
python_functions = test_*
5.結(jié)果斷言
from utils.LogUtil import my_log
import json
#1、定義封裝類
class AssertUtil:
#2拌汇、初始化數(shù)據(jù)柒桑,日志
def __init__(self):
self.log = my_log("AssertUtil")
#3、code相等
def assert_code(self,code,expected_code):
"""
驗證返回狀態(tài)碼
:param code:
:param expected_code:
:return:
"""
try:
assert int(code) == int(expected_code)
return True
except:
self.log.error("code error,code is %s,expected_code is %s"%(code,expected_code))
raise
#4噪舀、body相等
def assert_body(self,body,expected_body):
"""
驗證返回結(jié)果內(nèi)容相等
:param body:
:param expected_body:
:return:
"""
try :
assert body == expected_body
return True
except:
self.log.error("body error,body is %s,expected_body is %s"%(body,expected_body))
raise
#5魁淳、body包含
def assert_in_body(self,body,expected_body):
"""
驗證返回結(jié)果是否包含期望的結(jié)果
:param body:
:param expected_body:
:return:
"""
try:
body = json.dumps(body)
print(body)
assert expected_body in body
return True
except:
self.log.error("不包含或者body是錯誤,body is %s,expected_body is %s"%(body,expected_body))
raise
from utils.LogUtil import my_log
import pymysql
#1与倡、創(chuàng)建封裝類
class Mysql:
#2界逛、初始化數(shù)據(jù),連接數(shù)據(jù)庫纺座,光標(biāo)對象
def __init__(self,host,user,password,database,charset="utf8",port=3306):
self.log = my_log()
self.conn = pymysql.connect(
host=host,
user=user,
password=password,
database=database,
charset=charset,
port=port
)
self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
#3息拜、創(chuàng)建查詢、執(zhí)行方法
def fetchone(self,sql):
"""
單個查詢
:param sql:
:return:
"""
self.cursor.execute(sql)
return self.cursor.fetchone()
def fetchall(self,sql):
"""
多個查詢
:param sql:
:return:
"""
self.cursor.execute(sql)
return self.cursor.fetchall()
def exec(self,sql):
"""
執(zhí)行
:return:
"""
try:
if self.conn and self.cursor:
self.cursor.execute(sql)
self.conn.commit()
except Exception as ex:
self.conn.rollback()
self.log.error("Mysql 執(zhí)行失敗")
self.log.error(ex)
return False
return True
#4比驻、關(guān)閉對象
def __del__(self):
#關(guān)閉光標(biāo)對象
if self.cursor is not None:
self.cursor.close()
#關(guān)閉連接對象
if self.conn is not None:
self.cursor.close()
if __name__ == "__main__":
mysql = Mysql("211.103.136.242",
"test",
"test123456","meiduo",
charset="utf8",
port=7090)
#res = mysql.fetchall("select username,password from tb_users")
res = mysql.exec("update tb_users set first_name='python' where username = 'python'")
print(res)
#1该溯、創(chuàng)建db_conf.yml, db1,db2
#2、編寫數(shù)據(jù)庫基本信息
#3别惦、重構(gòu)Conf.py
#4狈茉、執(zhí)行
"""
#1、導(dǎo)入pymysql包
import pymysql
#2掸掸、連接database
conn = pymysql.connect(
host = "211.103.136.242",
user = "test",
password = "test123456",
database = "meiduo",
charset = "utf8",
port =7090
)
#3氯庆、獲取執(zhí)行sql的光標(biāo)對象
cursor = conn.cursor()
#4蹭秋、執(zhí)行sql
sql = "select username,password from tb_users"
cursor.execute(sql)
res = cursor.fetchone()
print(res)
#5、關(guān)閉對象
cursor.close()
conn.close()"""
6.數(shù)據(jù)驅(qū)動
Excel 讀取文件
import os
import xlrd
#目的:參數(shù)化堤撵,pytest list
#自定義異常
class SheetTypeError:
pass
#1仁讨、驗證文件是否存在,存在讀取实昨,不存在報錯
class ExcelReader:
def __init__(self,excel_file,sheet_by):
if os.path.exists(excel_file):
self.excel_file = excel_file
self.sheet_by = sheet_by
self._data=list()
else:
raise FileNotFoundError("文件不存在")
#2洞豁、讀取sheet方式,名稱荒给,索引
def data(self):
#存在不讀取丈挟,不存在讀取
if not self._data:
workbook = xlrd.open_workbook(self.excel_file)
if type(self.sheet_by) not in [str,int]:
raise SheetTypeError("請輸入Int or Str")
elif type(self.sheet_by) == int:
sheet = workbook.sheet_by_index(self.sheet_by)
elif type(self.sheet_by) == str:
sheet = workbook.sheet_by_name(self.sheet_by)
#3、讀取sheet內(nèi)容
#返回list志电,元素:字典
#格式[{"a":"a1","b":"b1"},{"a":"a2","b":"b2"}]
#1.獲取首行的信息
title = sheet.row_values(0)
#2.遍歷測試行曙咽,與首行組成dict,放在list
#1 循環(huán)挑辆,過濾首行例朱,從1開始
for col in range(1,sheet.nrows):
col_value = sheet.row_values(col)
#2 與首組成字典,放list
self._data.append(dict(zip(title, col_value)))
#4鱼蝉、結(jié)果返回
return self._data
# head = ["a","b"]
# value1 = ["a1","b1"]
# value2 = ["a2","b2"]
# data_list= list()
# #zip
# data_list.append(dict(zip(head,value1)))
# data_list.append(dict(zip(head,value2)))
# #print(dict(zip(head,value1)))
# #print(dict(zip(head,value2)))
# print(data_list)
if __name__ == "__main__":
reader = ExcelReader("../data/testdata.xlsx","美多商城接口測試")
print(reader.data())
發(fā)送郵件的封裝
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
#初始化
#smtp地址洒嗤,用戶名,密碼蚀乔,接收郵件者烁竭,郵件標(biāo)題,郵件內(nèi)容吉挣,郵件附件
class SendEmail:
def __init__(self,smtp_addr,username,password,recv,
title,content=None,file=None):
self.smtp_addr = smtp_addr
self.username = username
self.password = password
self.recv = recv
self.title = title
self.content = content
self.file = file
#發(fā)送郵件方法
def send_mail(self):
#MIME
msg = MIMEMultipart()
#初始化郵件信息
msg.attach(MIMEText(self.content,_charset="utf-8"))
msg["Subject"] = self.title
msg["From"] = self.username
msg["To"] = self.recv
#郵件附件
#判斷是否附件
if self.file:
#MIMEText讀取文件
att = MIMEText(open(self.file).read())
#設(shè)置內(nèi)容類型
att["Content-Type"] = 'application/octet-stream'
#設(shè)置附件頭
att["Content-Disposition"] = 'attachment;filename="%s"'%self.file
#將內(nèi)容附加到郵件主體中
msg.attach(att)
#登錄郵件服務(wù)器
self.smtp = smtplib.SMTP(self.smtp_addr,port=25)
self.smtp.login(self.username,self.password)
#發(fā)送郵件
self.smtp.sendmail(self.username,self.recv,msg.as_string())
if __name__ == "__main__":
#初始化類(self,smtp_addr,username,password,recv,
# title,content=None,file=None):
from config.Conf import ConfigYaml
email_info = ConfigYaml().get_email_info()
smtp_addr = email_info["smtpserver"]
username = email_info["username"]
password = email_info["password"]
recv = email_info["receiver"]
email = SendEmail(smtp_addr,username,password,recv,"測試")
email.send_mail()
#封裝公共方法
#應(yīng)用測試發(fā)送
》