闲话休扯,上需求:自动读取、执行excel里面的接口测试用例,测试完成后,返回错误结果并发送邮件通知。
分析:
1、设计excel表格
2、读取excel表格
3、拼接url,发送请求
4、汇总错误结果、发送邮件
开始实现:
1、设计excel接口用例表格,大概长这样:

依次为:用例编号、接口名称、接口主host、接口路由、请求方式、请求参数类型、请求参数、断言
这次案例中用到的接口,其实就是如何优雅的进行接口测试使用的快递查询接口,一时半会儿没找到好用的,之前写的也找不到了,只好作罢。
2、读取excel表格,获取每个用例的数据
- import xlrd
- import sys
-
- def test_cases_in_excel(test_case_file):
- test_case_file = os.path.join(os.getcwd(), test_case_file)
- # 获取测试用例全路径 如:E:\Python\httprunner\interface_excel\testcases.xlsx
- print(test_case_file)
- if not os.path.exists(test_case_file):
- print("测试用例excel文件存在或路径有误!")
- # 找不到指定测试文件,就退出程序 os.system("exit")是用来退出cmd的
- sys.exit()
- # 读取excel文件
- test_case = xlrd.open_workbook(test_case_file)
- # 获取第一个sheet,下标从0开始
- table = test_case.sheet_by_index(0)
- # 记录错误用例
- error_cases = []
- # 一张表格读取下来,其实就像个二维数组,无非是读取第一行的第几列的值,由于下标是从0开始,第一行是标题,所以从第二行开始读取数据
- for i in range(1, table.nrows):
- num = str(int(table.cell(i, 0).value)).replace("\n", "").replace("\r", "")
- api_name = table.cell(i, 1).value.replace("\n", "").replace("\r", "")
- api_host = table.cell(i, 2).value.replace("\n", "").replace("\r", "")
- request_url = table.cell(i, 3).value.replace("\n", "").replace("\r", "")
- method = table.cell(i, 4).value.replace("\n", "").replace("\r", "")
- request_data_type = table.cell(i, 5).value.replace("\n", "").replace("\r", "")
- request_data = table.cell(i, 6).value.replace("\n", "").replace("\r", "")
- check_point = table.cell(i, 7).value.replace("\n", "").replace("\r", "")
- print(num, api_name, api_host, request_url, method, request_data_type, request_data, check_point)
- try:
- # 调用接口请求方法,后面会讲到
- status, resp = interface_test(num, api_name, api_host, request_url, method,
- request_data_type, request_data, check_point)
- if status != 200 or check_point not in resp:
- # append只接收一个参数,所以要讲四个参数括在一起,当一个参数来传递
- # 请求失败,则向error_cases中增加一条记录
- error_cases.append((num + " " + api_name, str(status), api_host + request_url))
- except Exception as e:
- print(e)
- print("第{}个接口请求失败,请检查接口是否异常。".format(num))
- # 访问异常,也向error_cases中增加一条记录
- error_cases.append((num + " " + api_name, "请求失败", api_host + request_url))
- return error_cases
3、拼接url,判断请求方式(get/post),发送请求传入读取用例的各种参数,先判断请求方式,再拼接参数通过requests库来发送请求
-
- import requests
-
- def interface_test(num, api_name, api_host, request_url, method,
- request_data_type, request_data, check_point):
- # 构造请求headers
- headers = {'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8',
- 'X-Requested-With' : 'XMLHttpRequest',
- 'Connection' : 'keep-alive',
- 'Referer' : 'http://' + api_host,
- 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36'
- }
- # 判断请求方式,如果是GET,则调用get请求,POST调post请求,都不是,则抛出异常
- if method == "GET":
- r = requests.get(url=api_host+request_url, params=json.loads(request_data), headers=headers)
- # 获取请求状态码
- status = r.status_code
- # 获取返回值
- resp = r.text
- if status == 200:
- # 断言,判断设置的断言值,是否在返回值里面
- if check_point in str(r.text):
- print("第{}条用例'{}'执行成功,状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'执行失败!!!状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'执行失败!!!状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- elif method == "POST":
- # 跟GET里面差不多,就不一一注释了
- r = requests.post(url=api_host+request_url, params=json.loads(request_data), headers=headers)
- status = r.status_code
- resp = r.text
- if status == 200:
- if check_point in str(r.text):
- print("第{}条用例'{}'执行成功,状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'执行失败!!!状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'执行失败!!!状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'请求方式有误!!!请确认字段【Method】值是否正确,正确值为大写的GET或POST。".format(num, api_name))
- return 400, "请求方式有误"
4、汇总错误结果、发送邮件4.1、汇总错误结果,保存为简易html报告,并通过邮件发送到指定接收人
-
- def main():
- # 执行所以测试用例,获取错误的用例
- error_cases = test_cases_in_excel("testcases.xlsx")
- # 如果有错误接口,则开始构造html报告
- if len(error_cases) > 0:
- html = '接口自动化扫描,共有 ' + str(len(error_cases)) + ' 个异常接口,列表如下:' + '
接口 状态 接口地址 '- for test in error_cases:
- html = html + '
' + test[0] + ' ' + test[1] + ' ' + test[2] + ' ' - send_email(html)
- print(html)
- with open ("report.html", "w") as f:
- f.write(html)
- else:
- print("本次测试,所有用例全部通过")
- send_email("本次测试,所有用例全部通过")
4.2、构造邮件函数
先读取配置文件,新建config.yml配置文件,内容如下:
sender为发送邮件的邮箱,receiver为接收者着的邮箱,支持多个,smtpserver邮箱服务,username发送者邮箱少去后缀,password密码

- import yaml
-
- def get_conf():
- with open ("config.yml", "r", encoding='utf-8') as f:
- cfg = f.read()
- dic = yaml.load(cfg)
- sender = dic['email']['sender']
- receiver = dic['email']['receiver']
- smtpserver = dic['email']['smtpserver']
- username = dic['email']['username']
- password = dic['email']['password']
- print(sender, receiver, smtpserver, username, password)
- return sender, receiver, smtpserver, username, password
然后构造发送邮件的函数
- import smtplib
- import time
- from email.mime.multipart import MIMEMultipart
- from email.mime.text import MIMEText
- from email.mime.base import MIMEBase
- from email.header import Header
-
- def send_email(text):
- today = time.strftime('%Y.%m.%d',time.localtime(time.time()))
- sender, receiver, smtpserver, username, password = get_conf()
- # subject为邮件主题 text为邮件正文
- subject = "[api_test]接口自动化测试结果通知 {}".format(today)
- msg = MIMEText(text, 'html', 'utf-8')
- msg['Subject'] = subject
- msg['From'] = sender
- msg['To'] = "".join(receiver)
- smtp = smtplib.SMTP()
- smtp.connect(smtpserver)
- smtp.login(username, password)
- smtp.sendmail(sender, receiver, msg.as_string())
- smtp.quit()
以上内容就将需求实现了,由于现在很晚了(懒),上面所以函数就对在一个py文件里面了,来运行下吧

邮件一会儿就收到了

所有代码如下:
- #!/usr/bin/env python
- #-*- coding:utf-8 -*-
-
- '''
- 需求:自动读取、执行excel里面的接口测试用例,测试完成后,返回错误结果并发送邮件通知。
- 一步一步捋清需求:
- 1、设计excel表格
- 2、读取excel表格
- 3、拼接url,发送请求
- 4、汇总错误结果、发送邮件
- '''
- import xlrd
- import os
- import requests
- import json
- import yaml
- import smtplib
- import time
- import sys
- from email.mime.multipart import MIMEMultipart
- from email.mime.text import MIMEText
- from email.mime.base import MIMEBase
- from email.header import Header
-
-
- def test_cases_in_excel(test_case_file):
- test_case_file = os.path.join(os.getcwd(), test_case_file)
- # 获取测试用例全路径 如:E:\Python\httprunner\interface_excel\testcases.xlsx
- print(test_case_file)
- if not os.path.exists(test_case_file):
- print("测试用例excel文件存在或路径有误!")
- # 找不到指定测试文件,就退出程序 os.system("exit")是用来退出cmd的
- sys.exit()
- # 读取excel文件
- test_case = xlrd.open_workbook(test_case_file)
- # 获取第一个sheet,下标从0开始
- table = test_case.sheet_by_index(0)
- # 记录错误用例
- error_cases = []
- # 一张表格读取下来,其实就像个二维数组,无非是读取第一行的第几列的值,由于下标是从0开始,第一行是标题,所以从第二行开始读取数据
- for i in range(1, table.nrows):
- num = str(int(table.cell(i, 0).value)).replace("\n", "").replace("\r", "")
- api_name = table.cell(i, 1).value.replace("\n", "").replace("\r", "")
- api_host = table.cell(i, 2).value.replace("\n", "").replace("\r", "")
- request_url = table.cell(i, 3).value.replace("\n", "").replace("\r", "")
- method = table.cell(i, 4).value.replace("\n", "").replace("\r", "")
- request_data_type = table.cell(i, 5).value.replace("\n", "").replace("\r", "")
- request_data = table.cell(i, 6).value.replace("\n", "").replace("\r", "")
- check_point = table.cell(i, 7).value.replace("\n", "").replace("\r", "")
- print(num, api_name, api_host, request_url, method, request_data_type, request_data, check_point)
- try:
- # 调用接口请求方法,后面会讲到
- status, resp = interface_test(num, api_name, api_host, request_url, method,
- request_data_type, request_data, check_point)
- if status != 200 or check_point not in resp:
- # append只接收一个参数,所以要讲四个参数括在一起,当一个参数来传递
- # 请求失败,则向error_cases中增加一条记录
- error_cases.append((num + " " + api_name, str(status), api_host + request_url))
- except Exception as e:
- print(e)
- print("第{}个接口请求失败,请检查接口是否异常。".format(num))
- # 访问异常,也向error_cases中增加一条记录
- error_cases.append((num + " " + api_name, "请求失败", api_host + request_url))
- return error_cases
-
-
- def interface_test(num, api_name, api_host, request_url, method,
- request_data_type, request_data, check_point):
- # 构造请求headers
- headers = {'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8',
- 'X-Requested-With' : 'XMLHttpRequest',
- 'Connection' : 'keep-alive',
- 'Referer' : 'http://' + api_host,
- 'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36'
- }
- # 判断请求方式,如果是GET,则调用get请求,POST调post请求,都不是,则抛出异常
- if method == "GET":
- r = requests.get(url=api_host+request_url, params=json.loads(request_data), headers=headers)
- # 获取请求状态码
- status = r.status_code
- # 获取返回值
- resp = r.text
- if status == 200:
- # 断言,判断设置的断言值,是否在返回值里面
- if check_point in str(r.text):
- print("第{}条用例'{}'执行成功,状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'执行失败!!!状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'执行失败!!!状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- elif method == "POST":
- # 跟GET里面差不多,就不一一注释了
- r = requests.post(url=api_host+request_url, params=json.loads(request_data), headers=headers)
- status = r.status_code
- resp = r.text
- if status == 200:
- if check_point in str(r.text):
- print("第{}条用例'{}'执行成功,状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'执行失败!!!状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'执行失败!!!状态码为{},结果返回值为{}.".format(num, api_name, status, r.text))
- return status, resp
- else:
- print("第{}条用例'{}'请求方式有误!!!请确认字段【Method】值是否正确,正确值为大写的GET或POST。".format(num, api_name))
- return 400, "请求方式有误"
-
-
- def main():
- # 执行所以测试用例,获取错误的用例
- error_cases = test_cases_in_excel("testcases.xlsx")
- # 如果有错误接口,则开始构造html报告
- if len(error_cases) > 0:
- # html = '接口自动化扫描,共有 ' + str(len(error_cases)) + ' 个异常接口,列表如下:' + '
接口 状态 接口地址 接口返回值 '- html = '接口自动化扫描,共有 ' + str(len(error_cases)) + ' 个异常接口,列表如下:' + '
接口 状态 接口地址 '- for test in error_cases:
- # html = html + '
' + test[0] + ' ' + test[1] + ' ' + test[2] + ' ' + test[3] + ' ' - html = html + '
' + test[0] + ' ' + test[1] + ' ' + test[2] + ' ' - send_email(html)
- print(html)
- with open ("report.html", "w") as f:
- f.write(html)
- else:
- print("本次测试,所有用例全部通过")
- send_email("本次测试,所有用例全部通过")
-
-
- def get_conf():
- with open ("config.yml", "r", encoding='utf-8') as f:
- cfg = f.read()
- dic = yaml.load(cfg)
- # print(type(dic))
- # print(dic)
- sender = dic['email']['sender']
- receiver = dic['email']['receiver']
- smtpserver = dic['email']['smtpserver']
- username = dic['email']['username']
- password = dic['email']['password']
- print(sender, receiver, smtpserver, username, password)
- return sender, receiver, smtpserver, username, password
-
-
- def send_email(text):
- today = time.strftime('%Y.%m.%d',time.localtime(time.time()))
- sender, receiver, smtpserver, username, password = get_conf()
- # subject为邮件主题 text为邮件正文
- subject = "[api_test]接口自动化测试结果通知 {}".format(today)
- msg = MIMEText(text, 'html', 'utf-8')
- msg['Subject'] = subject
- msg['From'] = sender
- msg['To'] = "".join(receiver)
- smtp = smtplib.SMTP()
- smtp.connect(smtpserver)
- smtp.login(username, password)
- smtp.sendmail(sender, receiver, msg.as_string())
- smtp.quit()
-
-
- if __name__ == "__main__":
- # send_email("test")
- main()
View Code
思考:
需要改进的地方有很多:
1、增加日志:导入logging模块,代码里面的print一通copy即可,自己尝试哈
2、回写excel表格:xlrd既然可以读取excel文档,肯定可以写入的。可以新增一列,每次执行完用例,将结果写进去,自己去尝试哈
3、request data type没有做判断,这里偷懒了,因为只用了一个接口,而且大晚上在赶工,就没有做判断。可以参照判断请求方式(get/post)来写。
4、报告渣:1、可以尝试使用htmlreport库;2、也可以自己尝试使用一些前端框架生成,如bootstrap
5、未做持续集成:什么是持续集成?听起来高大上,说白了就是找个数据库或者其他玩意儿,将用例、执行结果等等,都存储起来。python有很多库,可以连接各种数据库(mysql、mongoDB),读取excel或者其他接口脚本文档,存入数据库;然后请求接口后,再从库里面读取出来。balabala......
6、无界面:没有界面,其实要不要都无所谓,毕竟只要维护一份excel表格即可。如果一定要的话,可以考虑使用django或者flask框架,构造web页面,将用例的导入导出、新增、编辑、发送请求,生成报告等等一系列操作,全部移交到前端。这就需要懂一点前端代码,如果有兴趣,你也可以尝试。
Python接口自动化测试零基础入门到精通(2023最新版)
-
相关阅读:
uniapp中的app和微信小程序来回跳转
SQL内连接——使用场景记录
每天5分钟复习OpenStack(七)内存虚拟化
RK平台使用MP4视频做开机动画以及卡顿问题
容器数据卷
STM32F103学习1-keil5工程建立的步骤和模板傻瓜教程
java线程池
java -- Stringbuild、Date和Calendar类
【贪心算法】独木舟上的旅行
小琳AI课堂:MASS模型——革新自然语言处理的预训练技术
-
原文地址:https://blog.csdn.net/ada4656/article/details/133861732