Python+unittest+requests+excel实现接口自动化测试框架


Posted in Python onDecember 23, 2020

环境:python3 + unittest + requests

  • Excel管理测试用例,
  • HTMLTestRunner生成测试报告
  • 测试完成后邮件发送测试报告
  • jsonpath方式做预期结果数据处理,后期多样化处理
  • 后期扩展,CI持续集成

发送邮件效果:

Python+unittest+requests+excel实现接口自动化测试框架

项目整体结构:

Python+unittest+requests+excel实现接口自动化测试框架

common模块代码

class IsInstance:
 
  def get_instance(self, value, check):
    flag = None
    if isinstance(value, str):
      if check == value:
        flag = True
      else:
        flag = False
    elif isinstance(value, float):
      if value - float(check) == 0:
        flag = True
      else:
        flag = False
    elif isinstance(value, int):
      if value - int(check) == 0:
        flag = True
      else:
        flag = False
    return flag
# logger.py
 
import logging
import time
import os
 
 
class MyLogging:
 
  def __init__(self):
    timestr = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
    lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../logs'))
    filename = lib_path + '/' + timestr + '.log' # 日志文件的地址
    self.logger = logging.getLogger() # 定义对应的程序模块名name,默认为root
    self.logger.setLevel(logging.INFO) # 必须设置,这里如果不显示设置,默认过滤掉warning之前的所有级别的信息
 
    sh = logging.StreamHandler() # 日志输出到屏幕控制台
    sh.setLevel(logging.INFO) # 设置日志等级
 
    fh = logging.FileHandler(filename=filename) # 向文件filename输出日志信息
    fh.setLevel(logging.INFO) # 设置日志等级
 
    # 设置格式对象
    formatter = logging.Formatter(
      "%(asctime)s %(filename)s[line:%(lineno)d]%(levelname)s - %(message)s") # 定义日志输出格式
 
    # 设置handler的格式对象
    sh.setFormatter(formatter)
    fh.setFormatter(formatter)
 
    # 将handler增加到logger中
    self.logger.addHandler(sh)
    self.logger.addHandler(fh)
 
 
if __name__ == "__main__":
  log = MyLogging().logger
  log.debug("debug")
  log.info("info")
  log.warning("warning")
  log.error("error")
  log.critical("critical")
# operate_excel.py
import xlrd
from xlrd import xldate_as_tuple
import openpyxl
import datetime
 
 
class ExcelData():
  def __init__(self, file_path, sheet_name):
    self.file_path = file_path
    self.sheet_name = sheet_name
    self.workbook = xlrd.open_workbook(self.file_path)
 
    # 获取工作表的内容
    self.table = self.workbook.sheet_by_name(self.sheet_name)
    # 获取第一行内容
    self.keys = self.table.row_values(0)
    # 获取行数
    self.rowNum = self.table.nrows
    # 获取列数
    self.colNum = self.table.ncols
 
  def readExcel(self):
    datas = []
    for i in range(1, self.rowNum):
      sheet_data = []
      for j in range(self.colNum):
        # 获取单元格类型
        c_type = self.table.cell(i, j).ctype
        # 获取单元格数据
        c_cell = self.table.cell_value(i, j)
        if c_type == 2 and c_cell % 1 == 0:
          c_cell = int(c_cell)
        elif c_type == 3:
          date = datetime.datetime(*xldate_as_tuple(c_cell, 0))
          c_cell = date.strftime('%Y/%d/%m %H:%M:%S')
        elif c_type == 4:
          c_cell = True if c_cell == 1 else False
        # sheet_data[self.keys[j]] = c_cell  # 字典
        sheet_data.append(c_cell)
      datas.append(sheet_data)
    return datas
 
  def write(self, rowNum, colNum, result):
    workbook = openpyxl.load_workbook(self.file_path)
    table = workbook.get_sheet_by_name(self.sheet_name)
    table = workbook.active
 
    # rows = table.max_row
    # cols = table.max_column
    # values = ['E','X','C','E','L']
    # for value in values:
    #   table.cell(rows + 1, 1).value = value
    #   rows = rows + 1
 
    # 指定单元格中写入数据
    table.cell(rowNum, colNum, result)
    workbook.save(self.file_path)
 
 
if __name__ == '__main__':
  file_path = "D:\python_data\接口自动化测试.xlsx"
  sheet_name = "测试用例"
  data = ExcelData(file_path, sheet_name)
  datas = data.readExcel()
  print(datas)
  print(type(datas))
  for i in datas:
    print(i)
 
  # data.write(2,12,"哈哈")
# send_email.py
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.mime.text import MIMEText
from config import read_email_config
import smtplib
 
 
def send_email(subject, mail_body, file_names=list()):
  # 获取邮件相关信息
  smtp_server = read_email_config.smtp_server
  port = read_email_config.port
  user_name = read_email_config.user_name
  password = read_email_config.password
  sender = read_email_config.sender
  receiver = read_email_config.receiver
 
  # 定义邮件内容
  msg = MIMEMultipart()
  body = MIMEText(mail_body, _subtype="html", _charset="utf-8")
  msg["Subject"] = Header(subject, "utf-8")
  msg["From"] = user_name
  msg["To"] = receiver
  msg.attach(body)
 
  # 附件:附件名称用英文
  for file_name in file_names:
    att = MIMEText(open(file_name, "rb").read(), "base64", "utf-8")
    att["Content-Type"] = "application/octet-stream"
    att["Content-Disposition"] = "attachment;filename='%s'" % (file_name)
    msg.attach(att)
 
  # 登录并发送邮件
  try:
    smtp = smtplib.SMTP()
    smtp.connect(smtp_server)
    smtp.login(user_name, password)
    smtp.sendmail(sender, receiver.split(','), msg.as_string())
  except Exception as e:
    print(e)
    print("邮件发送失败!")
  else:
    print("邮件发送成功!")
  finally:
    smtp.quit()
 
 
if __name__ == '__main__':
  subject = "测试标题"
  mail_body = "测试本文"
  receiver = "780156051@qq.com,hb_zhijun@163.com" # 接收人邮件地址 用逗号分隔
  file_names = [r'D:\PycharmProjects\AutoTest\result\2020-02-23 13_38_41report.html']
  send_email(subject, mail_body, receiver, file_names)
# send_request.py
 
import requests
import json
 
 
class RunMethod:
  # post请求
  def do_post(self, url, data, headers=None):
    res = None
    if headers != None:
      res = requests.post(url=url, json=data, headers=headers)
    else:
      res = requests.post(url=url, json=data)
    return res.json()
 
  # get请求
  def do_get(self, url, data=None, headers=None):
    res = None
    if headers != None:
      res = requests.get(url=url, data=data, headers=headers)
    else:
      res = requests.get(url=url, data=data)
    return res.json()
 
  def run_method(self, method, url, data=None, headers=None):
    res = None
    if method == "POST" or method == "post":
      res = self.do_post(url, data, headers)
    else:
      res = self.do_get(url, data, headers)
    return res

config模块

# coding:utf-8
# 邮件配置信息
 
[mysqlconf]
host = 127.0.0.1
port = 3306
user = root
password = root
db = test
# coding:utf-8
# 邮箱配置信息
# email_config.ini
 
[email]
smtp_server = smtp.qq.com
port = 465
sender = 780***51@qq.com
password = hrpk******baf
user_name = 780***51@qq.com
receiver = 780***51@qq.com,h***n@163.com
# coding:utf-8
from pymysql import connect, cursors
from pymysql.err import OperationalError
import os
import configparser
 
# read_db_config.py
 
# 读取DB配数据
# os.path.realpath(__file__):返回当前文件的绝对路径
# os.path.dirname(): 返回()所在目录
cur_path = os.path.dirname(os.path.realpath(__file__))
configPath = os.path.join(cur_path, "db_config.ini") # 路径拼接:/config/db_config.ini
conf = configparser.ConfigParser()
conf.read(configPath, encoding="UTF-8")
 
host = conf.get("mysqlconf", "host")
port = conf.get("mysqlconf", "port ")
user = conf.get("mysqlconf", "user")
password = conf.get("mysqlconf", "password")
port = conf.get("mysqlconf", "port")
# coding:utf-8
import os
import configparser
# 读取邮件数据
# os.path.realpath(__file__):返回当前文件的绝对路径
# os.path.dirname(): 返回()所在目录
 
# read_email_config.py
 
cur_path = os.path.dirname(os.path.realpath(__file__)) # 当前文件的所在目录
configPath = os.path.join(cur_path, "email_config.ini") # 路径拼接:/config/email_config.ini
conf = configparser.ConfigParser()
conf.read(configPath, encoding='UTF-8') # 读取/config/email_config.ini 的内容
 
# get(section,option) 得到section中option的值,返回为string类型
smtp_server = conf.get("email", "smtp_server")
sender = conf.get("email", "sender")
user_name = conf.get("email","user_name")
password = conf.get("email", "password")
receiver = conf.get("email", "receiver")
port = conf.get("email", "port")

testcase模块

# test_case.py
 
from common.operate_excel import *
import unittest
from parameterized import parameterized
from common.send_request import RunMethod
import json
from common.logger import MyLogging
import jsonpath
from common.is_instance import IsInstance
from HTMLTestRunner import HTMLTestRunner
import os
import time
 
lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../data"))
file_path = lib_path + "/" + "接口自动化测试.xlsx" # excel的地址
sheet_name = "测试用例"
log = MyLogging().logger
 
 
def getExcelData():
  list = ExcelData(file_path, sheet_name).readExcel()
  return list
 
 
class TestCase(unittest.TestCase):
 
  @parameterized.expand(getExcelData())
  def test_api(self, rowNumber, caseRowNumber, testCaseName, priority, apiName, url, method, parmsType, data,
         checkPoint, isRun, result):
    if isRun == "Y" or isRun == "y":
      log.info("【开始执行测试用例:{}】".format(testCaseName))
      headers = {"Content-Type": "application/json"}
      data = json.loads(data) # 字典对象转换为json字符串
      c = checkPoint.split(",")
      log.info("用例设置检查点:%s" % c)
      print("用例设置检查点:%s" % c)
      log.info("请求url:%s" % url)
      log.info("请求参数:%s" % data)
      r = RunMethod()
      res = r.run_method(method, url, data, headers)
      log.info("返回结果:%s" % res)
 
      flag = None
      for i in range(0, len(c)):
        checkPoint_dict = {}
        checkPoint_dict[c[i].split('=')[0]] = c[i].split('=')[1]
        # jsonpath方式获取检查点对应的返回数据
        list = jsonpath.jsonpath(res, c[i].split('=')[0])
        value = list[0]
        check = checkPoint_dict[c[i].split('=')[0]]
        log.info("检查点数据{}:{},返回数据:{}".format(i + 1, check, value))
        print("检查点数据{}:{},返回数据:{}".format(i + 1, check, value))
        # 判断检查点数据是否与返回的数据一致
        flag = IsInstance().get_instance(value, check)
 
      if flag:
        log.info("【测试结果:通过】")
        ExcelData(file_path, sheet_name).write(rowNumber + 1, 12, "Pass")
      else:
        log.info("【测试结果:失败】")
        ExcelData(file_path, sheet_name).write(rowNumber + 1, 12, "Fail")
 
      # 断言
      self.assertTrue(flag, msg="检查点数据与实际返回数据不一致")
    else:
      unittest.skip("不执行")
 
 
if __name__ == '__main__':
  # unittest.main()
  # Alt+Shift+f10 执行生成报告
 
  # 报告样式1
  suite = unittest.TestSuite()
  suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCase))
  now = time.strftime('%Y-%m-%d %H_%M_%S')
  report_path = r"D:\PycharmProjects\AutoTest\result\report.html"
  with open(report_path, "wb") as f:
    runner = HTMLTestRunner(stream=f, title="Esearch接口测试报告", description="测试用例执行情况", verbosity=2)
    runner.run(suite)

用例执行文件

import os
import time
import unittest
from HTMLTestRunner import HTMLTestRunner
from common.send_email import send_email
 
# run_case.py
 
# 获取当前py文件绝对路径
cur_path = os.path.dirname(os.path.realpath(__file__))
 
 
# 1: 加载测试用例
def all_test():
  case_path = os.path.join(cur_path, "testcase")
  suite = unittest.TestLoader().discover(start_dir=case_path, pattern="test_*.py", top_level_dir=None)
  return suite
 
 
# 2: 执行测试用例
def run():
  now = time.strftime("%Y_%m_%d_%H_%M_%S")
  # 测试报告路径
  file_name = os.path.join(cur_path, "report") + "/" + now + "-report.html"
  f = open(file_name, "wb")
  runner = HTMLTestRunner(stream=f, title="接口自动化测试报告",
              description="环境:windows 10 浏览器:chrome",
              tester="wangzhijun")
  runner.run(all_test())
  f.close()
 
 
# 3: 获取最新的测试报告
def get_report(report_path):
  list = os.listdir(report_path)
  list.sort(key=lambda x: os.path.getmtime(os.path.join(report_path, x)))
  print("测试报告:", list[-1])
  report_file = os.path.join(report_path, list[-1])
  return report_file
 
 
# 4: 发送邮件
def send_mail(subject, report_file, file_names):
  # 读取测试报告内容,作为邮件的正文内容
  with open(report_file, "rb") as f:
    mail_body = f.read()
  send_email(subject, mail_body, file_names)
 
 
if __name__ == "__main__":
  run()
  report_path = os.path.join(cur_path, "report") # 测试报告路径
  report_file = get_report(report_path) # 测试报告文件
  subject = "Esearch接口测试报告" # 邮件主题
  file_names = [report_file] # 邮件附件
  # 发送邮件
  send_mail(subject, report_file, file_names)

data:

Python+unittest+requests+excel实现接口自动化测试框架

report:

Python+unittest+requests+excel实现接口自动化测试框架

logs:

Python+unittest+requests+excel实现接口自动化测试框架

到此这篇关于Python+unittest+requests+excel实现接口自动化测试框架的文章就介绍到这了,更多相关Python 接口自动化测试内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
小结Python用fork来创建子进程注意事项
Jul 03 Python
python实现简单购物商城
May 21 Python
Python更新数据库脚本两种方法及对比介绍
Jul 27 Python
Python使用cx_Freeze库生成msi格式安装文件的方法
Jul 10 Python
python如何生成网页验证码
Jul 28 Python
对Python Class之间函数的调用关系详解
Jan 23 Python
python中pip的使用和修改下载源的方法
Jul 08 Python
python将类似json的数据存储到MySQL中的实例
Jul 12 Python
django2.2安装错误最全的解决方案(小结)
Sep 24 Python
python的time模块和datetime模块实例解析
Nov 29 Python
浅谈Python3多线程之间的执行顺序问题
May 02 Python
python os模块在系统管理中的应用
Jun 22 Python
用python计算文件的MD5值
Dec 23 #Python
python中lower函数实现方法及用法讲解
Dec 23 #Python
Python类型转换的魔术方法详解
Dec 23 #Python
python3 googletrans超时报错问题及翻译工具优化方案 附源码
Dec 23 #Python
python音频处理的示例详解
Dec 23 #Python
python 实现客户端与服务端的通信
Dec 23 #Python
python实现excel公式格式化的示例代码
Dec 23 #Python
You might like
Ajax+PHP 边学边练之四 表单
2009/11/27 PHP
thinkPHP中volist标签用法示例
2016/12/06 PHP
PDO::lastInsertId讲解
2019/01/29 PHP
document.getElementById介绍
2011/09/13 Javascript
分享JavaScript获取网页关闭与取消关闭的事件
2013/12/13 Javascript
javascript制作loading动画效果 loading效果
2014/01/14 Javascript
通过pjax实现无刷新翻页(兼容新版jquery)
2014/01/31 Javascript
JavaScript实现LI列表数据绑定的方法
2015/08/04 Javascript
分享Javascript实用方法二
2015/12/13 Javascript
jQuery文本框得到与失去焦点动态改变样式效果
2016/09/08 Javascript
BootStrap Validator使用注意事项(必看篇)
2016/09/28 Javascript
针对后台列表table拖拽比较实用的jquery拖动排序
2016/10/10 Javascript
js addDqmForPP给标签内属性值加上双引号的函数
2016/12/24 Javascript
BootStrap3中模态对话框的使用
2017/01/06 Javascript
使用JS组件实现带ToolTip验证框的实例代码
2017/08/23 Javascript
vuex学习之Actions的用法详解
2017/08/29 Javascript
详解小程序云开发攻略(解决最棘手的问题)
2019/09/30 Javascript
vue根据条件不同显示不同按钮的操作
2020/08/04 Javascript
python 动态获取当前运行的类名和函数名的方法
2014/04/15 Python
Python中操作文件之write()方法的使用教程
2015/05/25 Python
Python爬虫天气预报实例详解(小白入门)
2018/01/24 Python
简单了解Python matplotlib线的属性
2019/06/29 Python
6行Python代码实现进度条效果(Progress、tqdm、alive-progress​​​​​​​和PySimpleGUI库)
2020/01/06 Python
TensorFlow2.1.0安装过程中setuptools、wrapt等相关错误指南
2020/04/08 Python
python实现IOU计算案例
2020/04/12 Python
Ubuntu 20.04安装Pycharm2020.2及锁定到任务栏的问题(小白级操作)
2020/10/29 Python
德国街头和运动文化高品质商店:BSTN Store
2017/08/26 全球购物
英国Flybe航空官网:欧洲最大的独立支线廉价航空公司
2019/07/15 全球购物
阿拉伯书店:Jamalon
2019/07/24 全球购物
Linux面试题LINUX系统类
2015/11/25 面试题
介绍一下Prototype的$()函数,$F()函数,$A()函数都是什么作用?
2014/03/05 面试题
党校培训自我鉴定
2014/02/01 职场文书
2014年元旦联欢会活动策划方案
2014/02/16 职场文书
人事文员岗位职责
2015/02/04 职场文书
教师读书笔记
2015/06/29 职场文书
《落花生》教学反思
2016/02/16 职场文书