python--接口自动化

日志文件

import logging
from logging import handlers
from conf.setting import LOG_PATH


class Logger(object):
# 日志级别关系映射
level_relations = {
'debug': logging.DEBUG,
'info': logging.INFO,
'warning': logging.WARNING,
'error': logging.ERROR,
'crit': logging.CRITICAL
}

def __init__(self, filename, level='info', when='D', back_count=3,
fmt='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'):
self.logger = logging.getLogger(filename)
self.logger.setLevel(self.level_relations.get(level)) # 设置日志级别
format_str = logging.Formatter(fmt)
sh = logging.StreamHandler()
sh.setFormatter(format_str)
th = handlers.TimedRotatingFileHandler(filename=filename, when=when,
backupCount=back_count, encoding='utf-8')
th.setFormatter(format_str)
self.logger.addHandler(sh)
self.logger.addHandler(th)


log = Logger(LOG_PATH, level='debug').logger # 直接在本文件实例化,以后导入log就行,不需要实例化了

if __name__ == '__main__':
log = Logger('nhy.log')
log.logger.debug('i的是100')
log.logger.info('开机')
log.logger.warning('警告 飞机没油了')
log.logger.error('错误 飞机要爆炸')


报告文件
import time
from conf.setting import REPORT_PATH
import os


class HtmlReport(object):
__style_html = '''
<style type="text/css">
body {
font:normal 68% verdana,arial,helvetica;
color:#000000;
}
table tr td, table tr th {
font-size: 68%;
}
table.details tr th{
color: #ffffff;
font-weight: bold;
text-align:center;
background:#2674a6;
}
table.details tr td{
background:#eeeee0;
}
h1 {
margin: 0px 0px 5px; font: 165% verdana,arial,helvetica
}
h2 {
margin-top: 1em; margin-bottom: 0.5em; font: bold 125% verdana,arial,helvetica
}
h3 {
margin-bottom: 0.5em; font: bold 115% verdana,arial,helvetica
}
.Failure {
font-weight:bold; color:red;
}


img
{
border-width: 0px;
}

.expand_link
{
position=absolute;
right: 0px;
width: 27px;
top: 1px;
height: 27px;
}

.page_details
{
display: none;
}

.page_details_expanded
{
display: block;
display/* hide this definition from IE5/6 */: table-row;
}


</style>
<script language="JavaScript">
function show(details_id)
{
var close = 'page_details';
var show = 'page_details_expanded';
if (document.getElementById(details_id).className==close){
document.getElementById(details_id).className = show;
}
else {
document.getElementById(details_id).className = close;
}

}

</script>
'''
__report_html = '''
<!DOCTYPE html>
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>接口测试报告</title>
{style}
</head>
<body>
<h1>接口测试报告</h1>
<table width="100%">
<tr>
<td align="left">测试时间: {date}</td>
</tr>
</table>
<hr size="1">
<h2>测试概况</h2>
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="details" align="center">
<tr valign="top">
<th>用例总数</th><th>通过数量</th><th>失败数量</th><th>运行时间</th>
</tr>
<tr valign="top" class="">
<td align="center">{all}</td><td align="center">{ok}</td><td align="center">{fail}</td><td align="center">{run_time} s</td>
</tr>
</table>
<hr align="center" width="95%" size="1">
<h2>接口详细</h2>
<table width="95%" cellspacing="2" cellpadding="5" border="0" class="details" align="center">
<tr valign="top">
<th>所属项目</th><th>模块</th><th>用例描述</th><th>URL</th><th>测试人员</th><th>用例状态</th><th></th>
</tr>{case_res}</table>
<hr align="center" width="95%" size="1">
</body>
</html>

'''
__case_html = '''
<tr valign="top" class="">
<td>{project}</td><td align="center">{model}</td><td align="center">{detail}</td><td align="center">{url}</td><td align="center">{tester}</td><td align="center">{status}</td><td align="center"><a href="#" onclick="show('page_details_{case_id}');">查看接口详细</a></td>
</tr>
<tr class="page_details" id="page_details_{case_id}">
<td bgcolor="#FF0000" colspan="8">
<div align="center">
<b>请求/返回 "{project}"</b>
<table width="95%" cellspacing="1" cellpadding="1" border="0" bgcolor="#2674A6" bordercolor="#000000">
<tr>
<th>请求报文</th><th>返回报文</th>
</tr>
<tr>
<td align="center" style="width :300px;word-break: break-all;"><span>{request}</span></td><td align="center" style="width :300px;word-break: break-all;" ><span>{response}</span></td>

</tr>
</table>
</div>
</td>
</tr>

'''

def __init__(self, report_dic):
'''

:param report_dic:生成报告需要用的字典
{
"all": 5,#运行用例数量
"ok": 4,#通过数量
"fail": 1,#失败数量
"run_time": 100,#运行时间,单位s
"case_res": [{}],#每条用例的执行结果,
case_res:
{
"case_id":"001",#用例id
"project":"易品",#所属项目
"model":"登录",#模块
"detail":"正常登录",#用例标题
"url":"http://10.165.124.28:8080/q", #请求url
"tester":"牛牛", #测试人员
"status":"通过",#测试结果
"request":"a=1&b=2",#请求报文
"response":"{'code':200,'msg':'操作成功'}"#返回报文
}
}
'''
self.report_dic = report_dic

def report(self):
res_list_html = ''
res_list = self.report_dic.get('case_res')
for res in res_list:
res_list_html += self.__case_html.format(**res)
self.report_dic['case_res'] = res_list_html
self.report_dic['style'] = self.__style_html
self.report_dic['date'] = time.strftime('%Y/%m/%d %H:%M:%S')
self.__write_file()

def __write_file(self):
self.file_name = os.path.join(REPORT_PATH, '{date}_TestReport.html'.format(date=time.strftime('%Y%m%d%H%M%S')))
with open(self.file_name, 'w', encoding='utf-8') as fw:
fw.write(self.__report_html.format(**self.report_dic))


if __name__ == '__main__':
res_list = [
{
"case_id": "1",
"project": "易品",
"model": "登录",
"detail": "正常登录",
"url": "http://10.165.124.28:8080/q",
"tester": "牛牛",
"status": "通过",
"request": "a=1&b=2",
"response": "{'code':200,'msg':'操作成功'}"
}
]

all = {
"all": 5,
"ok": 4,
"fail": 1,
"run_time": 100,
"case_res": res_list,
"date": time.strftime('%Y/%m/%d %H:%M:%S')
}

a = HtmlReport(all)
a.report()



发送邮件文件
import smtplib
import os
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import base64


# qq授权码
# lfuhiziuplykbgdd
# vavqwyhdvjdzcabh
class SendMail(object):
def __init__(self, username, passwd, recv, title, content,
file=None, ssl=False,
email_host='smtp.126.com', port=25, ssl_port=465):
# :param username: 用户名
# :param passwd: 密码
# :param recv: 收件人,多个要传list ['a@qq.com','b@qq.com]
# :param title: 邮件标题
# :param content: 邮件正文
# :param file: 附件路径,如果不在当前目录下,要写绝对路径,默认没有附件
# :param ssl: 是否安全链接,默认为普通
# :param email_host: smtp服务器地址,默认为163服务器
# :param port: 非安全链接端口,默认为25
# :param ssl_port: 安全链接端口,默认为465
self.username = username # 用户名
self.passwd = passwd # 密码
self.recv = recv # 收件人,多个要传list ['a@qq.com','b@qq.com]
self.title = title # 邮件标题
self.content = content # 邮件正文
self.file = file # 附件路径,如果不在当前目录下,要写绝对路径
self.email_host = email_host # smtp服务器地址
self.port = port # 普通端口
self.ssl = ssl # 是否安全链接
self.ssl_port = ssl_port # 安全链接端口
# self.smtp = smtp

def send_mail(self):
msg = MIMEMultipart()
# 发送内容的对象
if self.file: # 处理附件的
file_name = os.path.split(self.file)[-1] # 只取文件名,不取路径
try:
f = open(self.file, 'rb').read()
except Exception as e:
raise Exception('附件打不开!', e)
else:
att = MIMEText(f, "base64", "utf-8")
att["Content-Type"] = 'application/octet-stream'
# base64.b64encode(file_name.encode()).decode()
new_file_name = '=?utf-8?b?' + base64.b64encode(file_name.encode()).decode() + '?='
# 这里是处理文件名为中文名的,必须这么写
att["Content-Disposition"] = 'attachment; filename="%s"' % new_file_name
msg.attach(att)
msg.attach(MIMEText(self.content)) # 邮件正文的内容
msg['Subject'] = self.title # 邮件主题
msg['From'] = self.username # 发送者账号
msg['To'] = ','.join(self.recv) # 接收者账号列表
if self.ssl:
self.smtp = smtplib.SMTP_SSL(self.email_host, port=self.ssl_port)
else:
self.smtp = smtplib.SMTP(self.email_host, port=self.port)
# 发送邮件服务器的对象
self.smtp.login(self.username, self.passwd)
try:
self.smtp.sendmail(self.username, self.recv, msg.as_string())
pass
except Exception as e:
print('出错了。。', e)
else:
print('发送成功!')
self.smtp.quit()


if __name__ == '__main__':
m = SendMail(
username='389688559@qq.com',
passwd='lfuhiziuplykbgdd',
recv=['wangsilei@126.com', '511402865@qq.com'],
title='过年好',
content='新年快乐',
file=r'C:\Users\Wang\Desktop\新年快乐.txt',
ssl=True,
)
m.send_mail()



工具文件,含多种方法
import xlrd
import os
from common.MyLog import log
import requests
from xlutils.copy import copy
import time
from common.发送邮件最终版 import SendMail
from conf.setting import MAIL_USER_INFO, MAIL_PASSWORD, RECV


def read_case(case_path): # 读用例
if os.path.isfile(case_path):
book = xlrd.open_workbook(case_path)
sheet = book.sheet_by_index(0)
all_case = [] # 所有的测试用例
for row in range(1, sheet.nrows):
all_case.append(sheet.row_values(row)[:8])
log.debug('用例信息为:%s' % all_case)
log.info('总共读取了%s条测试用例' % len(all_case))

return all_case
else:
log.error('读取用例不存在,用例路径为%s' % case_path)
raise Exception('用例不存在!')


class MyRequest(object): # 调接口
@classmethod
def post(cls, url, data):
data = cls.str_to_dict(data)
try:
res = requests.post(url, data=data).text
except Exception as e:
log.error('接口调用出错,错误信息为%s,url为%s' % (e, url))
res = e
return res, data

@classmethod
def get(cls, url, data):
data = cls.str_to_dict(data)
try:
res = requests.get(url, data=data).text
except Exception as e:
log.error('接口调用出错,错误信息为%s,url为%s' % (e, url))
res = e
return res, data

@classmethod
def str_to_dict(cls, st: str):
# a=1&b=2&c=3
# 1. &分割 ['a=1', 'b=2', 'c=3']
# 2. ['a', '1']
res = {}
if st.strip():
for d in st.split('&'):
j = d.split('=')
res[j[0]] = j[1]
return res


def check_res(expected, res): # 校验结果
# error_code=0,userId=1
"""
{
"error_code": 0,
"login_info": {
"login_time": "20180311155222",
"sign": "4beba93fceae97c997f40fd424696691",
"userId": 1
}
}
"""
new_res = res.replace('": "', '=').replace('": ', '=')
for c in expected.split(','):
# ['error_code=0', 'userId=1']
if c not in new_res:
return '失败'
return '通过'


def write_excel(case_path, all_res): # 结果写回excel
# all_res存放所有的测试结果
book1 = xlrd.open_workbook(case_path)
book2 = copy(book1) # 拷贝一份原来的
sheet = book2.get_sheet(0) # 获取第几个sheet页
line = 1 # 行号
for res in all_res:
sheet.write(line, 8, str(res[0]))
sheet.write(line, 9, res[1])
sheet.write(line, 10, res[2])
sheet.write(line, 11, res[3])
line += 1
book2.save(case_path)


# all_res = [
# ['{"usrname":"niuhanyang"}', '{xxxx}', '通过', '原宝青'],
# ['{"usrname":"niuhanyang"}', '{xxxx}', '通过', '原宝青'],
# ['{"usrname":"niuhanyang"}', '{xxxx}', '通过', '原宝青']
#
# ]
# write_excel(r'C:\Users\wangsilei\Desktop\测试用例.xls', all_res)


def send_report(all_count, pass_count, report_file=None): # 发送测试报告
if report_file:
title = time.strftime('%Y-%m-%d %H:%M:%S') + '接口测试报告'
content = '''
大家好!
本次接口测试,共运行{all}条测试用例
通过{ok}条
失败{fail}条
测试报告详细信息见附件!
'''.format(all=all_count, ok=pass_count, fail=(all_count - pass_count))
m = SendMail(MAIL_USER_INFO, MAIL_PASSWORD, RECV, title, content, file=report_file)
m.send_mail()



run文件
import os
import sys
import time

from common import tools
from conf.setting import CASE_PATH, TESTER
from common.tools import MyRequest
from common.report import HtmlReport

BASE_PATH = os.path.dirname(
os.path.dirname(
os.path.abspath(__file__)
)
)
sys.path.insert(0, BASE_PATH)


class RunCase(object):
def find_case(self):
for case_file in os.listdir(CASE_PATH):
if case_file.endswith('.xls'):
# 获取用例
self.case_path = os.path.join(CASE_PATH, case_file)
all_case = tools.read_case(self.case_path)
self.run_case(all_case)

def run_case(self, all_case):
excel_res = [] # 写入excel的结果使用的
report_res = {} # 给生成的函数使用的
case_res = [] # 存放每个用例的结果
pass_count = 0 # 通过的次数
for case in all_case:
project = case[0]
model = case[1]
case_id = case[2]
case_detail = case[3]
url = case[4]
method = case[5]
req_data = case[6]
check = case[7]
if method.upper() == 'POST':
response, data = MyRequest.post(url, req_data)
else:
response, data = MyRequest.get(url, req_data)
case_status = tools.check_res(check, response) # 获取用例执行结果
pass_count = pass_count + 1 if case_status == '通过' else pass_count
tmp_case_res = self.create_report(case_id, project, model, case_detail, url, TESTER, case_status, data, response)
case_res.append(tmp_case_res)
excel_res.append([data, response, case_status, TESTER]) # 把每条用例的结果加入到写excel的那个里面
tools.write_excel(self.case_path, excel_res)
all_cases_num = len(all_case)
report_res['all'] = all_cases_num # 总共的用例数
report_res['ok'] = pass_count # 通过的数量
report_res['fail'] = all_cases_num - pass_count # 失败的数量
report_res['case_res'] = case_res # 每条用例的结果
report_res['date'] = time.strftime('%Y-%m-%d %H:%M:%S')
report_res['run_time'] = 1
report_obj = HtmlReport(report_res) # 实例化对象
report_obj.report() # 生成报告
tools.send_report(all_cases_num, pass_count, report_obj.file_name) # 发送测试报告
print('测试运行完成。。。')

def create_report(self, case_id, project, model, detail, url, tester, status, request, response):
return {
'case_id': case_id,
'project': project,
'model': model,
'detail': detail,
'url': url,
'tester': tester,
'status': status,
'request': request,
'response': response,
}

run = RunCase()
run.find_case()



配置文件
import os

BASE_PATH = os.path.dirname(
os.path.dirname(
os.path.abspath(__file__)
)
)
LOG_PATH = os.path.join(BASE_PATH, 'logs', 'atp.log') # 日志路径
REPORT_PATH = os.path.join(BASE_PATH, 'report') # 报告路径
CASE_PATH = os.path.join(BASE_PATH, 'cases') # 用例的路径
MAIL_USER_INFO = 'wangsilei@126.com'
MAIL_PASSWORD = 'xxxxxxxx'
RECV = ['389688559@qq.com', '356367764@qq.com']
TESTER = '王思磊'
posted @ 2018-03-15 10:32  王思磊  阅读(197)  评论(0编辑  收藏  举报