小言_互联网的博客

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

407人阅读  评论(0)
  • 环境:python3 + unittest + requests
  • Excel管理测试用例,
  • HTMLTestRunner生成测试报告
  • 测试完成后邮件发送测试报告
  • jsonpath方式做预期结果数据处理,后期多样化处理
  • 后期扩展,CI持续集成

发送邮件效果:

项目整体结构:

common模块代码


   
  1. class IsInstance:
  2. def get_instance(self, value, check):
  3. flag = None
  4. if isinstance(value, str):
  5. if check == value:
  6. flag = True
  7. else:
  8. flag = False
  9. elif isinstance(value, float):
  10. if value - float(check) == 0:
  11. flag = True
  12. else:
  13. flag = False
  14. elif isinstance(value, int):
  15. if value - int(check) == 0:
  16. flag = True
  17. else:
  18. flag = False
  19. return flag

   
  1. # logger.py
  2. import logging
  3. import time
  4. import os
  5. class MyLogging:
  6. def __init__(self):
  7. timestr = time.strftime( '%Y%m%d%H%M%S', time.localtime(time.time()))
  8. lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../logs'))
  9. filename = lib_path + '/' + timestr + '.log' # 日志文件的地址
  10. self.logger = logging.getLogger() # 定义对应的程序模块名name,默认为root
  11. self.logger.setLevel(logging.INFO) # 必须设置,这里如果不显示设置,默认过滤掉warning之前的所有级别的信息
  12. sh = logging.StreamHandler() # 日志输出到屏幕控制台
  13. sh.setLevel(logging.INFO) # 设置日志等级
  14. fh = logging.FileHandler(filename=filename) # 向文件filename输出日志信息
  15. fh.setLevel(logging.INFO) # 设置日志等级
  16. # 设置格式对象
  17. formatter = logging.Formatter(
  18. "%(asctime)s %(filename)s[line:%(lineno)d]%(levelname)s - %(message)s") # 定义日志输出格式
  19. # 设置handler的格式对象
  20. sh.setFormatter(formatter)
  21. fh.setFormatter(formatter)
  22. # 将handler增加到logger中
  23. self.logger.addHandler(sh)
  24. self.logger.addHandler(fh)
  25. if __name__ == "__main__":
  26. log = MyLogging().logger
  27. log.debug( "debug")
  28. log.info( "info")
  29. log.warning( "warning")
  30. log.error( "error")
  31. log.critical( "critical")

   
  1. # operate_excel.py
  2. import xlrd
  3. from xlrd import xldate_as_tuple
  4. import openpyxl
  5. import datetime
  6. class ExcelData():
  7. def __init__(self, file_path, sheet_name):
  8. self.file_path = file_path
  9. self.sheet_name = sheet_name
  10. self.workbook = xlrd.open_workbook(self.file_path)
  11. # 获取工作表的内容
  12. self.table = self.workbook.sheet_by_name(self.sheet_name)
  13. # 获取第一行内容
  14. self.keys = self.table.row_values( 0)
  15. # 获取行数
  16. self.rowNum = self.table.nrows
  17. # 获取列数
  18. self.colNum = self.table.ncols
  19. def readExcel(self):
  20. datas = []
  21. for i in range( 1, self.rowNum):
  22. sheet_data = []
  23. for j in range(self.colNum):
  24. # 获取单元格类型
  25. c_type = self.table.cell(i, j).ctype
  26. # 获取单元格数据
  27. c_cell = self.table.cell_value(i, j)
  28. if c_type == 2 and c_cell % 1 == 0:
  29. c_cell = int(c_cell)
  30. elif c_type == 3:
  31. date = datetime.datetime(*xldate_as_tuple(c_cell, 0))
  32. c_cell = date.strftime( '%Y/%d/%m %H:%M:%S')
  33. elif c_type == 4:
  34. c_cell = True if c_cell == 1 else False
  35. # sheet_data[self.keys[j]] = c_cell # 字典
  36. sheet_data.append(c_cell)
  37. datas.append(sheet_data)
  38. return datas
  39. def write(self, rowNum, colNum, result):
  40. workbook = openpyxl.load_workbook(self.file_path)
  41. table = workbook.get_sheet_by_name(self.sheet_name)
  42. table = workbook.active
  43. # rows = table.max_row
  44. # cols = table.max_column
  45. # values = ['E','X','C','E','L']
  46. # for value in values:
  47. # table.cell(rows + 1, 1).value = value
  48. # rows = rows + 1
  49. # 指定单元格中写入数据
  50. table.cell(rowNum, colNum, result)
  51. workbook.save(self.file_path)
  52. if __name__ == '__main__':
  53. file_path = "D:\python_data\接口自动化测试.xlsx"
  54. sheet_name = "测试用例"
  55. data = ExcelData(file_path, sheet_name)
  56. datas = data.readExcel()
  57. print(datas)
  58. print(type(datas))
  59. for i in datas:
  60. print(i)
  61. # data.write(2,12,"哈哈")

   
  1. # send_email.py
  2. from email.mime.multipart import MIMEMultipart
  3. from email.header import Header
  4. from email.mime.text import MIMEText
  5. from config import read_email_config
  6. import smtplib
  7. def send_email(subject, mail_body, file_names=list()):
  8. # 获取邮件相关信息
  9. smtp_server = read_email_config.smtp_server
  10. port = read_email_config.port
  11. user_name = read_email_config.user_name
  12. password = read_email_config.password
  13. sender = read_email_config.sender
  14. receiver = read_email_config.receiver
  15. # 定义邮件内容
  16. msg = MIMEMultipart()
  17. body = MIMEText(mail_body, _subtype= "html", _charset= "utf-8")
  18. msg[ "Subject"] = Header(subject, "utf-8")
  19. msg[ "From"] = user_name
  20. msg[ "To"] = receiver
  21. msg.attach(body)
  22. # 附件:附件名称用英文
  23. for file_name in file_names:
  24. att = MIMEText(open(file_name, "rb").read(), "base64", "utf-8")
  25. att[ "Content-Type"] = "application/octet-stream"
  26. att[ "Content-Disposition"] = "attachment;filename='%s'" % (file_name)
  27. msg.attach(att)
  28. # 登录并发送邮件
  29. try:
  30. smtp = smtplib.SMTP()
  31. smtp.connect(smtp_server)
  32. smtp.login(user_name, password)
  33. smtp.sendmail(sender, receiver.split( ','), msg.as_string())
  34. except Exception as e:
  35. print(e)
  36. print( "邮件发送失败!")
  37. else:
  38. print( "邮件发送成功!")
  39. finally:
  40. smtp.quit()
  41. if __name__ == '__main__':
  42. subject = "测试标题"
  43. mail_body = "测试本文"
  44. receiver = "780156051@qq.com,hb_zhijun@163.com" # 接收人邮件地址 用逗号分隔
  45. file_names = [ r'D:\PycharmProjects\AutoTest\result\2020-02-23 13_38_41report.html']
  46. send_email(subject, mail_body, receiver, file_names)

   
  1. # send_request.py
  2. import requests
  3. import json
  4. class RunMethod:
  5. # post请求
  6. def do_post(self, url, data, headers=None):
  7. res = None
  8. if headers != None:
  9. res = requests.post(url=url, json=data, headers=headers)
  10. else:
  11. res = requests.post(url=url, json=data)
  12. return res.json()
  13. # get请求
  14. def do_get(self, url, data=None, headers=None):
  15. res = None
  16. if headers != None:
  17. res = requests.get(url=url, data=data, headers=headers)
  18. else:
  19. res = requests.get(url=url, data=data)
  20. return res.json()
  21. def run_method(self, method, url, data=None, headers=None):
  22. res = None
  23. if method == "POST" or method == "post":
  24. res = self.do_post(url, data, headers)
  25. else:
  26. res = self.do_get(url, data, headers)
  27. return res

config模块


   
  1. # coding:utf-8
  2. # 邮件配置信息
  3. [mysqlconf]
  4. host = 127.0 .0 .1
  5. port = 3306
  6. user = root
  7. password = root
  8. db = test

   
  1. # coding:utf-8
  2. # 邮箱配置信息
  3. # email_config.ini
  4. [email]
  5. smtp_server = smtp.qq.com
  6. port = 465
  7. sender = 780*** 51@qq.com
  8. password = hrpk******baf
  9. user_name = 780*** 51@qq.com
  10. receiver = 780*** 51@qq.com,h***n@ 163.com

   
  1. # coding:utf-8
  2. from pymysql import connect, cursors
  3. from pymysql.err import OperationalError
  4. import os
  5. import configparser
  6. # read_db_config.py
  7. # 读取DB配数据
  8. # os.path.realpath(__file__):返回当前文件的绝对路径
  9. # os.path.dirname(): 返回()所在目录
  10. cur_path = os.path.dirname(os.path.realpath(__file__))
  11. configPath = os.path.join(cur_path, "db_config.ini") # 路径拼接:/config/db_config.ini
  12. conf = configparser.ConfigParser()
  13. conf.read(configPath, encoding= "UTF-8")
  14. host = conf.get( "mysqlconf", "host")
  15. port = conf.get( "mysqlconf", "port ")
  16. user = conf.get( "mysqlconf", "user")
  17. password = conf.get( "mysqlconf", "password")
  18. port = conf.get( "mysqlconf", "port")

   
  1. # coding:utf-8
  2. import os
  3. import configparser
  4. # 读取邮件数据
  5. # os.path.realpath(__file__):返回当前文件的绝对路径
  6. # os.path.dirname(): 返回()所在目录
  7. # read_email_config.py
  8. cur_path = os.path.dirname(os.path.realpath(__file__)) # 当前文件的所在目录
  9. configPath = os.path.join(cur_path, "email_config.ini") # 路径拼接:/config/email_config.ini
  10. conf = configparser.ConfigParser()
  11. conf.read(configPath, encoding= 'UTF-8') # 读取/config/email_config.ini 的内容
  12. # get(section,option) 得到section中option的值,返回为string类型
  13. smtp_server = conf.get( "email", "smtp_server")
  14. sender = conf.get( "email", "sender")
  15. user_name = conf.get( "email", "user_name")
  16. password = conf.get( "email", "password")
  17. receiver = conf.get( "email", "receiver")
  18. port = conf.get( "email", "port")

testcase模块


   
  1. # test_case.py
  2. from common.operate_excel import *
  3. import unittest
  4. from parameterized import parameterized
  5. from common.send_request import RunMethod
  6. import json
  7. from common.logger import MyLogging
  8. import jsonpath
  9. from common.is_instance import IsInstance
  10. from HTMLTestRunner import HTMLTestRunner
  11. import os
  12. import time
  13. lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../data"))
  14. file_path = lib_path + "/" + "接口自动化测试.xlsx" # excel的地址
  15. sheet_name = "测试用例"
  16. log = MyLogging().logger
  17. def getExcelData():
  18. list = ExcelData(file_path, sheet_name).readExcel()
  19. return list
  20. class TestCase(unittest.TestCase):
  21. @parameterized.expand(getExcelData())
  22. def test_api(self, rowNumber, caseRowNumber, testCaseName, priority, apiName, url, method, parmsType, data,
  23. checkPoint, isRun, result):
  24. if isRun == "Y" or isRun == "y":
  25. log.info( "【开始执行测试用例:{}】".format(testCaseName))
  26. headers = { "Content-Type": "application/json"}
  27. data = json.loads(data) # 字典对象转换为json字符串
  28. c = checkPoint.split( ",")
  29. log.info( "用例设置检查点:%s" % c)
  30. print( "用例设置检查点:%s" % c)
  31. log.info( "请求url:%s" % url)
  32. log.info( "请求参数:%s" % data)
  33. r = RunMethod()
  34. res = r.run_method(method, url, data, headers)
  35. log.info( "返回结果:%s" % res)
  36. flag = None
  37. for i in range( 0, len(c)):
  38. checkPoint_dict = {}
  39. checkPoint_dict[c[i].split( '=')[ 0]] = c[i].split( '=')[ 1]
  40. # jsonpath方式获取检查点对应的返回数据
  41. list = jsonpath.jsonpath(res, c[i].split( '=')[ 0])
  42. value = list[ 0]
  43. check = checkPoint_dict[c[i].split( '=')[ 0]]
  44. log.info( "检查点数据{}:{},返回数据:{}".format(i + 1, check, value))
  45. print( "检查点数据{}:{},返回数据:{}".format(i + 1, check, value))
  46. # 判断检查点数据是否与返回的数据一致
  47. flag = IsInstance().get_instance(value, check)
  48. if flag:
  49. log.info( "【测试结果:通过】")
  50. ExcelData(file_path, sheet_name).write(rowNumber + 1, 12, "Pass")
  51. else:
  52. log.info( "【测试结果:失败】")
  53. ExcelData(file_path, sheet_name).write(rowNumber + 1, 12, "Fail")
  54. # 断言
  55. self.assertTrue(flag, msg= "检查点数据与实际返回数据不一致")
  56. else:
  57. unittest.skip( "不执行")
  58. if __name__ == '__main__':
  59. # unittest.main()
  60. # Alt+Shift+f10 执行生成报告
  61. # 报告样式1
  62. suite = unittest.TestSuite()
  63. suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestCase))
  64. now = time.strftime( '%Y-%m-%d %H_%M_%S')
  65. report_path = r"D:\PycharmProjects\AutoTest\result\report.html"
  66. with open(report_path, "wb") as f:
  67. runner = HTMLTestRunner(stream=f, title= "Esearch接口测试报告", description= "测试用例执行情况", verbosity= 2)
  68. runner.run(suite)

用例执行文件


   
  1. import os
  2. import time
  3. import unittest
  4. from HTMLTestRunner import HTMLTestRunner
  5. from common.send_email import send_email
  6. # run_case.py
  7. # 获取当前py文件绝对路径
  8. cur_path = os.path.dirname(os.path.realpath(__file__))
  9. # 1: 加载测试用例
  10. def all_test():
  11. case_path = os.path.join(cur_path, "testcase")
  12. suite = unittest.TestLoader().discover(start_dir=case_path, pattern= "test_*.py", top_level_dir= None)
  13. return suite
  14. # 2: 执行测试用例
  15. def run():
  16. now = time.strftime( "%Y_%m_%d_%H_%M_%S")
  17. # 测试报告路径
  18. file_name = os.path.join(cur_path, "report") + "/" + now + "-report.html"
  19. f = open(file_name, "wb")
  20. runner = HTMLTestRunner(stream=f, title= "接口自动化测试报告",
  21. description= "环境:windows 10 浏览器:chrome",
  22. tester= "wangzhijun")
  23. runner.run(all_test())
  24. f.close()
  25. # 3: 获取最新的测试报告
  26. def get_report(report_path):
  27. list = os.listdir(report_path)
  28. list.sort(key= lambda x: os.path.getmtime(os.path.join(report_path, x)))
  29. print( "测试报告:", list[ -1])
  30. report_file = os.path.join(report_path, list[ -1])
  31. return report_file
  32. # 4: 发送邮件
  33. def send_mail(subject, report_file, file_names):
  34. # 读取测试报告内容,作为邮件的正文内容
  35. with open(report_file, "rb") as f:
  36. mail_body = f.read()
  37. send_email(subject, mail_body, file_names)
  38. if __name__ == "__main__":
  39. run()
  40. report_path = os.path.join(cur_path, "report") # 测试报告路径
  41. report_file = get_report(report_path) # 测试报告文件
  42. subject = "Esearch接口测试报告" # 邮件主题
  43. file_names = [report_file] # 邮件附件
  44. # 发送邮件
  45. send_mail(subject, report_file, file_names)

data:

report:

logs:

 

有需要源码的朋友,可以加QQ群获取源码。


转载:https://blog.csdn.net/zhijun0901/article/details/106500585
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场