zoukankan      html  css  js  c++  java
  • python+requests+excel+unittest+ddt接口自动化数据驱动并生成html报告

    1.环境准备:

      python3.6
      requests
      xlrd
      openpyxl
      HTMLTestRunner_api

    2.目前实现的功能:

      封装requests请求方法
      在excel填写接口请求参数
      运行完后,重新生成一个excel报告,结果写入excel
      用unittest+ddt数据驱动模式执行
      HTMLTestRunner生成可视化的html报告
      对于没有关联的单个接口请求是可以批量执行的,需要登录的话写到setUpclass里的session里保持cookies
      token关联的不能实现
      logging日志文件暂时未加入

    3.目前已知的缺陷:

      无法实现参数关联:上个请求的结果是下个请求的参数,如token
      接口请求参数名有重复的,目前未处理,如key1=value1&key1=value2,两个key都一样,这种需要用元组存储,目前暂时未判断
      生成的excel样式未处理,后期慢慢优化样式
      python新手可能遇到模块导入报错问题

    项目结构

    excel测试数据

    xlrd读excel数据

    1.先从excel里面读取测试数据,返回字典格式

     1 # coding:utf-8
     2 
     3 # 作者:上海-悠悠
     4 # QQ群:226296743
     5 
     6 import xlrd
     7 class ExcelUtil():
     8     def __init__(self, excelPath, sheetName="Sheet1"):
     9         self.data = xlrd.open_workbook(excelPath)
    10         self.table = self.data.sheet_by_name(sheetName)
    11         # 获取第一行作为key值
    12         self.keys = self.table.row_values(0)
    13         # 获取总行数
    14         self.rowNum = self.table.nrows
    15         # 获取总列数
    16         self.colNum = self.table.ncols
    17 
    18     def dict_data(self):
    19         if self.rowNum <= 1:
    20             print("总行数小于1")
    21         else:
    22             r = []
    23             j = 1
    24             for i in list(range(self.rowNum-1)):
    25                 s = {}
    26                 # 从第二行取对应values值
    27                 s['rowNum'] = i+2
    28                 values = self.table.row_values(j)
    29                 for x in list(range(self.colNum)):
    30                     s[self.keys[x]] = values[x]
    31                 r.append(s)
    32                 j += 1
    33             return r
    34 
    35 if __name__ == "__main__":
    36     filepath = "debug_api.xlsx"
    37     sheetName = "Sheet1"
    38     data = ExcelUtil(filepath, sheetName)
    39     print(data.dict_data())
    40 openpyxl写入数据
    41 
    42 1.再封装一个写入excel数据的方法
    43 
    44 # coding:utf-8
    45 from openpyxl import load_workbook
    46 import openpyxl
    47 
    48 # 作者:上海-悠悠
    49 # QQ群:226296743
    50 
    51 def copy_excel(excelpath1, excelpath2):
    52     '''复制excek,把excelpath1数据复制到excelpath2'''
    53     wb2 = openpyxl.Workbook()
    54     wb2.save(excelpath2)
    55     # 读取数据
    56     wb1 = openpyxl.load_workbook(excelpath1)
    57     wb2 = openpyxl.load_workbook(excelpath2)
    58     sheets1 = wb1.sheetnames
    59     sheets2 = wb2.sheetnames
    60     sheet1 = wb1[sheets1[0]]
    61     sheet2 = wb2[sheets2[0]]
    62     max_row = sheet1.max_row         # 最大行数
    63     max_column = sheet1.max_column   # 最大列数
    64 
    65     for m in list(range(1,max_row+1)):
    66         for n in list(range(97,97+max_column)):   # chr(97)='a'
    67             n = chr(n)                            # ASCII字符
    68             i ='%s%d'% (n, m)                     # 单元格编号
    69             cell1 = sheet1[i].value               # 获取data单元格数据
    70             sheet2[i].value = cell1               # 赋值到test单元格
    71 
    72     wb2.save(excelpath2)                 # 保存数据
    73     wb1.close()                          # 关闭excel
    74     wb2.close()
    75 
    76 class Write_excel(object):
    77     '''修改excel数据'''
    78     def __init__(self, filename):
    79         self.filename = filename
    80         self.wb = load_workbook(self.filename)
    81         self.ws = self.wb.active  # 激活sheet
    82 
    83     def write(self, row_n, col_n, value):
    84         '''写入数据,如(2,3,"hello"),第二行第三列写入数据"hello"'''
    85         self.ws.cell(row_n, col_n).value = value
    86         self.wb.save(self.filename)
    87 
    88 if __name__ == "__main__":
    89     copy_excel("debug_api.xlsx", "testreport.xlsx")
    90     wt = Write_excel("testreport.xlsx")
    91     wt.write(4, 5, "HELLEOP")
    92     wt.write(4, 6, "HELLEOP")

    封装request请求方法

    1.把从excel读处理的数据作为请求参数,封装requests请求方法,传入请求参数,并返回结果

    2.为了不污染测试的数据,出报告的时候先将测试的excel复制都应该新的excel

    3.把测试返回的结果,在新的excel里面写入数据

     1 # coding:utf-8
     2 import json
     3 import requests
     4 from excelddtdriver.common.readexcel import ExcelUtil
     5 from excelddtdriver.common.writeexcel import copy_excel, Write_excel
     6 
     7 # 作者:上海-悠悠
     8 # QQ群:226296743
     9 
    10 
    11 def send_requests(s, testdata):
    12     '''封装requests请求'''
    13     method = testdata["method"]
    14     url = testdata["url"]
    15     # url后面的params参数
    16     try:
    17         params = eval(testdata["params"])
    18     except:
    19         params = None
    20     # 请求头部headers
    21     try:
    22         headers = eval(testdata["headers"])
    23         print("请求头部:%s" % headers)
    24     except:
    25         headers = None
    26     # post请求body类型
    27     type = testdata["type"]
    28 
    29     test_nub = testdata['id']
    30     print("*******正在执行用例:-----  %s  ----**********" % test_nub)
    31     print("请求方式:%s, 请求url:%s" % (method, url))
    32     print("请求params:%s" % params)
    33 
    34     # post请求body内容
    35     try:
    36         bodydata = eval(testdata["body"])
    37     except:
    38         bodydata = {}
    39 
    40     # 判断传data数据还是json
    41     if type == "data":
    42         body = bodydata
    43     elif type == "json":
    44         body = json.dumps(bodydata)
    45     else:
    46         body = bodydata
    47     if method == "post": print("post请求body类型为:%s ,body内容为:%s" % (type, body))
    48 
    49     verify = False
    50     res = {}   # 接受返回数据
    51 
    52     try:
    53         r = s.request(method=method,
    54                       url=url,
    55                       params=params,
    56                       headers=headers,
    57                       data=body,
    58                       verify=verify
    59                        )
    60         print("页面返回信息:%s" % r.content.decode("utf-8"))
    61         res['id'] = testdata['id']
    62         res['rowNum'] = testdata['rowNum']
    63         res["statuscode"] = str(r.status_code)  # 状态码转成str
    64         res["text"] = r.content.decode("utf-8")
    65         res["times"] = str(r.elapsed.total_seconds())   # 接口请求时间转str
    66         if res["statuscode"] != "200":
    67             res["error"] = res["text"]
    68         else:
    69             res["error"] = ""
    70         res["msg"] = ""
    71         if testdata["checkpoint"] in res["text"]:
    72             res["result"] = "pass"
    73             print("用例测试结果:   %s---->%s" % (test_nub, res["result"]))
    74         else:
    75             res["result"] = "fail"
    76         return res
    77     except Exception as msg:
    78         res["msg"] = str(msg)
    79         return res
    80 
    81 def wirte_result(result, filename="result.xlsx"):
    82     # 返回结果的行数row_nub
    83     row_nub = result['rowNum']
    84     # 写入statuscode
    85     wt = Write_excel(filename)
    86     wt.write(row_nub, 8, result['statuscode'])       # 写入返回状态码statuscode,第8列
    87     wt.write(row_nub, 9, result['times'])            # 耗时
    88     wt.write(row_nub, 10, result['error'])            # 状态码非200时的返回信息
    89     wt.write(row_nub, 12, result['result'])           # 测试结果 pass 还是fail
    90     wt.write(row_nub, 13, result['msg'])           # 抛异常
    91 
    92 if __name__ == "__main__":
    93     data = ExcelUtil("debug_api.xlsx").dict_data()
    94     print(data[0])
    95     s = requests.session()
    96     res = send_requests(s, data[0])
    97     copy_excel("debug_api.xlsx", "result.xlsx")
    98     wirte_result(res, filename="result.xlsx")

    测试用例unittest+ddt

    1.测试用例用unittest框架组建,并用ddt数据驱动模式,批量执行用例

     1 # coding:utf-8
     2 import unittest
     3 import ddt
     4 import os
     5 import requests
     6 from excelddtdriver.common import base_api
     7 from excelddtdriver.common import readexcel
     8 from excelddtdriver.common import writeexcel
     9 
    10 # 作者:上海-悠悠
    11 # QQ群:226296743
    12 
    13 # 获取demo_api.xlsx路径
    14 curpath = os.path.dirname(os.path.realpath(__file__))
    15 testxlsx = os.path.join(curpath, "demo_api.xlsx")
    16 
    17 # 复制demo_api.xlsx文件到report下
    18 report_path = os.path.join(os.path.dirname(curpath), "report")
    19 reportxlsx = os.path.join(report_path, "result.xlsx")
    20 
    21 testdata = readexcel.ExcelUtil(testxlsx).dict_data()
    22 @ddt.ddt
    23 class Test_api(unittest.TestCase):
    24     @classmethod
    25     def setUpClass(cls):
    26         cls.s = requests.session()
    27         # 如果有登录的话,就在这里先登录了
    28         writeexcel.copy_excel(testxlsx, reportxlsx) # 复制xlsx
    29 
    30     @ddt.data(*testdata)
    31     def test_api(self, data):
    32         # 先复制excel数据到report
    33         res = base_api.send_requests(self.s, data)
    34 
    35         base_api.wirte_result(res, filename=reportxlsx)
    36         # 检查点 checkpoint
    37         check = data["checkpoint"]
    38         print("检查点->:%s"%check)
    39         # 返回结果
    40         res_text = res["text"]
    41         print("返回实际结果->:%s"%res_text)
    42         # 断言
    43         self.assertTrue(check in res_text)
    44 
    45 if __name__ == "__main__":
    46     unittest.main()

    生成报告

    1.用HTMLTestRunner生成html报告,我这里改了下名称,改成了HTMLTestRunner_api.py
    此文件跟selenium的报告是通用的,github可下载https://github.com/yoyoketang/selenium_report/tree/master/selenium_report

     1 # coding=utf-8
     2 import unittest
     3 import time
     4 from excelddtdriver.common import HTMLTestRunner_api
     5 import os
     6 
     7 # 作者:上海-悠悠
     8 # QQ群:226296743
     9 
    10 curpath = os.path.dirname(os.path.realpath(__file__))
    11 report_path = os.path.join(curpath, "report")
    12 if not os.path.exists(report_path): os.mkdir(report_path)
    13 case_path = os.path.join(curpath, "case")
    14 
    15 def add_case(casepath=case_path, rule="test*.py"):
    16     '''加载所有的测试用例'''
    17     # 定义discover方法的参数
    18     discover = unittest.defaultTestLoader.discover(casepath,
    19                                                   pattern=rule,)
    20 
    21     return discover
    22 
    23 def run_case(all_case, reportpath=report_path):
    24     '''执行所有的用例, 并把结果写入测试报告'''
    25     htmlreport = reportpath+r"
    esult.html"
    26     print("测试报告生成地址:%s"% htmlreport)
    27     fp = open(htmlreport, "wb")
    28     runner = HTMLTestRunner_api.H全部折叠 折叠标题:
    29 View Code
    30   显示行号    行内代码
    31 TMLTestRunner(stream=fp,
    32                                                verbosity=2,
    33                                                title="测试报告",
    34                                                description="用例执行情况")
    35 
    36     # 调用add_case函数返回值
    37     runner.run(all_case)
    38     fp.close()
    39 
    40 if __name__ == "__main__":
    41     cases = add_case()
    42     run_case(cases)

    2.生成的excel报告

    3.生成的html报告

  • 相关阅读:
    (转)eclipse安装jetty
    (转)Java compiler level does not match解决方法
    (转)关于eclipse的TestNG的插件安装方法
    win7 远程桌面连接过程
    (转)IntelliJ IDEA 破解方法
    (转) Eclipse Maven 编译错误 Dynamic Web Module 3.1 requires Java 1.7 or newer 解决方案
    (转)@ContextConfiguration注解说明
    (转)java中/r与/n还有/r/n的区别
    (转)eclipse导入Gradle项目
    tomcat架构分析(valve机制)
  • 原文地址:https://www.cnblogs.com/111testing/p/9822596.html
Copyright © 2011-2022 走看看