本次写的是针对有代码基础的,没基础建议先去学基础,以下所有描述内容都是我已经在公司项目实践成功的!仅供参考

整体思路:
1、接口自动化用的是Python中unittest框架
2、所有的测试数据用例存放Excel表
3、封装一套读取和写入的Excel方法
4、重写request方法(为了从Excel读取数据后对数据作分析和判断并在测试报告生成相关信息)

5、通过HTMLTestRunner运行测试用例生成网页版报告
6、将自动化脚本放到公司git上,方便其他人员获取你的代码进行编写脚本,后面会具体讲如何获取代码和提交代码(让运维人员给你开通个git账号,自己注册登录就可以了)
7、通过Jenkins构建任务,定时自动运行git上自动化脚本,后面会具体讲如何配置Jenkins

先看看我的接口自动化整个目录结构和每个文件具体是干嘛的:

一、读取表格的代码:

 import xlrd,os,copy

 import sys,os

 #这三行代码是解决文件路径问题

 curPath = os.path.abspath(os.path.dirname(__file__))

 rootPath = os.path.split(curPath)[0]

 sys.path.append(rootPath)

 class ExcelUtil():

     list=[]

     list1 = []

     def __init__(self,excelpath,sheetname='Sheet1'):

         self.data=xlrd.open_workbook(excelpath)

         self.table=self.data.sheet_by_name(sheetname)

         #获取第一行作为key值

         self.keys=self.table.row_values(0)

         #获取总行数

         self.rowNum=self.table.nrows

         #获取总列数

         self.colNum=self.table.ncols

     #此方法有俩个用处:1、获取关闭或打开的case 2、不同模块的用例也可以通过该方法区分开来

     def open_case(self):

         exceldata = ExcelUtil(os.path.abspath(rootPath+'/Case/Ddt_case_api/TestCase.xlsx'), 'Sheet1')

         list = []

         list1 = []

         list2=[]

         for i in exceldata.dict_data():

             a = i['control_case']  # 这是在Excel加的开关case的字段

             if a == '':

                 list.append(i)

             elif a=='mobile_请先登录':

                 list1.append(i)

             elif a=='B_请先登录':

                 list2.append(i)

         return  list,list1,list2

         # print(len(list))

     def dict_data(self):

         if self.rowNum<=1:

             print('总行数小于1')

         else:

             r=[]

             j=1

             for i in range(self.rowNum-1):

                 s={}

                 s['rowNum']=i+2

                 values=self.table.row_values(j)

                 for x in range(self.colNum):

                     s[self.keys[x]]=values[x]

                 r.append(s)

                 j+=1

             return r

 #通过下面这个入口进行调试

 if __name__=='__main__':

     a=ExcelUtil('D:\Business_ManageMent\Case\Ddt_case_api\TestCase.xlsx')

     b=a.open_case()

     print(b)

二、写入表格代码:

 from openpyxl import load_workbook

 import openpyxl

 import xlrd

 def Copy_excel(exclepath1,excelpath2):

 #把excle1数据复制到excel2

     wb2=openpyxl.Workbook()

     wb2.save(excelpath2)

     wb1=load_workbook(exclepath1)

     wb2=load_workbook(excelpath2)

     sheets1=wb1.sheetnames

     sheets2=wb2.sheetnames

     sheet1=wb1[sheets1[0]]

     sheet2=wb2[sheets2[0]]

     maxrow=sheet1.max_row

     maxcolum=sheet1.max_column

     for m in range(1,maxrow+1):

         for n in range(97,97+maxcolum):

             n=chr(n)

             i='%s%d'%(n,m)

             cell1=sheet1[i].value

             sheet2[i]=cell1

     wb2.save(excelpath2)

     wb1.close()

     wb2.close()

 class Write_excel():

     def __init__(self,filename):

         self.filename=filename

         self.wb=load_workbook(self.filename)

 #激活sheet

         self.ws=self.wb.active

     def write(self,row_n,col_n,value):

         self.ws.cell(row_n,col_n).value=value

         self.wb.save(self.filename)

 #通过下面入口进行调试

 if  __name__=='__main__':

     Copy_excel('D:\Business_ManageMent\Case\Ddt_case_api\TestCase.xlsx','D:\Business_ManageMent\Case\\result.xlsx')

     wt=Write_excel('D:\Business_ManageMent\Case\\result.xlsx')

     wt.write(1,2,'hello')

 

三、重写request方法及将接口返回结果根据自己的需要写入拷贝的那张Excel表中

 import json
import requests
from Tool_class.read_excel_fz import ExcelUtil
from Tool_class.writeexcel_fz import Copy_excel, Write_excel def send_requests(s, testdata):
'''封装requests请求'''
#获取Excel标格中表头为method的数据
method = testdata["method"]
# 获取Excel标格中表头为url的数据
url = testdata["url"]
try:
#eval函数可以将读取到的参数内容转化成字典格式
# 获取Excel标格中表头为params的数据
params = eval(testdata["params"])
except:
params = None
# 请求头部headers
try:
# 获取Excel标格中表头为headers的数据
headers = eval(testdata["headers"])
print("请求头部:%s" % headers)
except:
headers = None # post请求body类型
# 获取Excel标格中表头为type的数据
type = testdata["type"]
# 获取Excel标格中表头为id的数据
test_nub = testdata['id']
print("*******正在执行用例:----- %s ----**********" % test_nub)
print("请求方式:%s, 请求url:%s" % (method, url))
print("请求params:%s" % params)
# post请求body内容
try:
# 获取Excel标格中表头为body的数据
bodydata = eval(testdata["body"])
except:
bodydata = {}
# 判断传data数据还是json
if type == "json":
#json.dumps将字典数据转成json格式,因为不同的接口传递参数是不同的,有的是传data,有的传json
body= json.dumps(bodydata)
elif type == "data":
body = bodydata
else:
body = bodydata if type=='json':
print("post请求body类型为:%s ,body内容为:%s" % (type,body))
elif method=='post':
print("post请求body类型为:%s ,body内容为:%s" % (type,body))
verify = False
res = {} # 接受返回数据 try:
r = s.request(method=method,
url=url,
params=params,
headers=headers,
data=body,
verify=verify
)
print("页面返回信息:%s" % r.json())
res['id'] = testdata['id']
res['rowNum'] = testdata['rowNum']
res["statuscode"] = str(r.status_code) # 状态码转成str
res["text"] = r.json()
res["times"] = str(r.elapsed.total_seconds()) # 接口请求时间转str
if res["statuscode"] != "":
res["error"] = "服务错误,接口未请求成功"
res["msg"] = str(res["text"])
else:
res["error"] = ""
res["msg"] = ""
if testdata["checkpoint"] == res["text"]['msg']:
res["result"] = "pass"
print("用例测试结果: %s---->%s" % (test_nub, res["result"]))
else:
res["result"] = "fail"
return res
except Exception as msg:
res["msg"] = str(msg)
return res
#将运行返回的结果,根据自己需要,需要要哪些结果就把哪些结果写入拷贝的那份Excel中
def wirte_result(result, filename="D:\Business_ManageMent\Case\\result.xlsx"):
# 返回结果的行数row_nub
row_nub = result['rowNum']
# 写入statuscode
wt = Write_excel(filename)
wt.write(row_nub, 7, result['statuscode']) # 写入返回状态码statuscode,第8列
wt.write(row_nub, 12, result['times']) # 耗时
wt.write(row_nub, 14, result['error']) # 状态码非200时的返回信息
wt.write(row_nub, 13, result['result']) # 测试结果 pass 还是fail
wt.write(row_nub, 15, result['msg']) # 抛异常

四、定义发送邮件和创建测试用例套件

 import time,os
import smtplib
import unittest
from Commons import HTMLTestRunner_jpg
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import email.mime.multipart
from email.mime.application import MIMEApplication
from Case import * # test_dir = os.path.abspath(os.path.join(os.getcwd(), ".."))
# now = time.strftime('%y_%m_%d %H_%M_%S')
# filename = (os.path.abspath('../Report') + '\\' + now + 'result.html')
# print(filename)
# fp = open(filename, 'wb')
import sys,os
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
#定义发送邮件
class Send():
def __init__(self):
self.flie_dir=rootPath+'\Report'
self.lists = os.listdir(self.flie_dir)
#将所有的报告按时间从小到大大排序
self.lists.sort(key=lambda fn: os.path.getmtime(self.flie_dir + '\\' + fn))
#取报告集合中最后一个报告即为最新的测试报告
self.new_file = os.path.join(self.flie_dir, self.lists[-1])
def send_mail(self):
now=time.strftime('%y:%m:%d:%H:%M:%S')
sender = '1063126729@qq.com'
recever= 'steve@wemart.cn'
msg = MIMEMultipart()
content = '最新接口测试报告,详情请下载附件查看,生成时间为:%s'%(now)
txt = email.mime.text.MIMEText(content, 'plain', 'utf-8')
msg.attach(txt)
msg['Subject']='接口自动化测试报告'
msg['date']=now
#添加附件
att = MIMEText(open(self.new_file, "rb").read(), "base64", "utf-8")
att["Content-Type"] = "application/octet-stream"
att["Content-Disposition"] = 'attachment; filename= "Report.html"'
msg.attach(att)
server=smtplib.SMTP_SSL(port=465)
server.connect('smtp.qq.com')
server.login('1063126729@qq.com','lhrcqszwzqafbcjf')
server.sendmail(sender,recever,msg.as_string())
server.quit()
print('邮件已发送')
#创建一个测试套件,将所有的用例添加到测试套件
def creatsuit(slef):
test_dir =rootPath+'\Case'
suit=unittest.TestSuite()
discover=unittest.defaultTestLoader.discover(test_dir,pattern='test*.py',top_level_dir=None)
for test_suit in discover:
for case in test_suit:
suit.addTest(case)
return suit

这里说明一下,excel表格自己新建一份,名字命名好,表头各个字段自己喜欢命名啥就命名啥,但注意代码中涉及到表头字段的也要相应调整,保持俩者一致。下面我贴出我存放用例的excel表格样式,供参考:

A:控制开关case    B:case名称   C:接口请求方法  D:接口地址  E:传参类型    F:请求头   G:状态码   H:检查点    I:get请求是传的参数     J:post请求时传的参数   K可以不要,这是我当时调试用的

L:接口响应时间  M:运行结果失败获成功   N:提示接口报错     O:接口返回的报错信息     其中G、L、M、N、O是不用填写的,这是为了复制该份表格时,要写入数据到复制的那份表格中用的

aaarticlea/png;base64,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" alt="" />

aaarticlea/png;base64,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" alt="" />

五、前四部分都是一些封装的东西,都是为了第五部分调用准备的,下面的代码是利用unittest框架去组织测试用例,因为我通过ddt数据驱动的,所以这部分代码就比较简洁了,如果你把测试数据都写在代码中,这是不利于维护的,看上去也很繁琐,几千条测试用例那要写多少

 import unittest
import ddt
import os
import requests
from Commons import base_api
from Tool_class import read_excel_fz
from Tool_class import writeexcel_fz
from Case.Hand_code_case.Login_case.Test_stor_login02 import *
import os,copy #获取当前文件位置路径
curpath = os.path.dirname(os.path.realpath(__file__))
# 获取TestCase.xlsx路径
testxlsx = os.path.join(curpath, "TestCase.xlsx")
#获取curpath位置的上一层目录位置
report_path = os.path.join(os.path.dirname(curpath))
#获取测试结果表格的目录位置
reportxlsx = os.path.join(report_path, "result.xlsx")
#创建读取表格的对象
testdata = read_excel_fz.ExcelUtil(testxlsx)
#获取表格中需要运行的数据或不需要运行的数据
cases=testdata.open_case()
#表格中打开的case
case=cases[0]
#表格中关闭的case
case_mobile=cases[1] @ddt.ddt
class Test_api(unittest.TestCase):
u'''B2C-API'''
@classmethod
def setUpClass(cls):
# 如果有登录的话,就在这里先登录了
cls.s = requests.Session()
# 复制xlsx
writeexcel_fz.Copy_excel(testxlsx, reportxlsx) #采用装饰器,在运行case之前都会先运行这个,这里的case是表格里打开的用例,也就是我需要运行的数据
@ddt.data(*case)
def test_api_01(self, data):
#先复制excel数据到Case文件夹下面
res = base_api.send_requests(self.s, data)
base_api.wirte_result(res, filename=reportxlsx)
#检查点 checkpoint
check = data["checkpoint"]
print("检查点->:%s"%check)
#返回结果
res_text = res["text"]
print("返回实际结果->:%s"%res_text)
#将接口返回的结果的键和值取到,通过键是否存在,再利用返回的值去和预期结果做断言
for m,n in res_text.items():
if m=='data' and m=='msg':
self.assertTrue(res_text['data']!=None)
self.assertTrue(res_text['msg'] == check)
elif 'data' not in m:
self.assertTrue(res_text['msg']==check)

六、上面将用例组织好了,接下来就是通过HTMLTestRunner模块运行并生成报告了,注:HTMLTestRunner模块自己去百度下载,可以将内容直接复制,然后在你的工程目录下建一个py文件将内容拷贝进去即可


 import sys,os
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath) import unittest,time,os
from Commons import HTMLTestRunner_jpg
from email.header import Header
from email.mime.text import MIMEText
from Commons.send_mail_report import Send #定义一个当前时间戳
now = time.strftime('%y_%m_%d %H_%M_%S')
#以时间给报告命名,这样就不会重复了
filename = rootPath+'\Report'+'\\'+ now + 'result.html'
fp=open(filename,'wb')
a = Send()
runner = HTMLTestRunner_jpg.HTMLTestRunner(stream=fp, title='测试报告', description='执行情况:')
runner.run(a.creatsuit())
fp.close()
#调用发送邮件的方法
a.send_mail()


七、Jenkins配置

然后回到任务首页,点击任务后面按钮立即构建,打开控制台即可查看运行记录和结果,如图:

以上所有的步骤已经完成了整个项目的构建,大家针对自己的项目可以拿上面的代码加以修改,其实最重要的是思路和良好的代码基础,我没有针对工具安装进行详细说,这个自己百度!自动化并不难,教程也很多,要学会加以总结并融汇贯通。后期主要跟新我学Python的历程,从基础到高级,再到利用Python实战做项目,欢迎关注

Unittest框架+ddt数据驱动+HTMLTestRunner+sendmail(自动发送测试报告)+git+Jenkins的更多相关文章

  1. 解惑unittest框架中导入HTMLTestRunner模块后正常运行却无法生成HTML报告问题

    1.HTMLTestRunner介绍 HTMLTestRunner是一个第三方的unittest HTML报告库,用于python单元测试框架的TestRunner.它是生成一个HTML报告,以一目了 ...

  2. python Unittest+excel+ddt数据驱动测试

    #!user/bin/env python # coding=utf- # @Author : Dang # @Time : // : # @Email : @qq.com # @File : # @ ...

  3. unittest框架(二)单元测试及测试报告

    如果要自测代码,可使用单元测试,需要导入unittest模块,import unittest即可. 例如,自测一个计算连个数相除的函数,代码如下: import unittest def calc(a ...

  4. unittest框架下的HTMLTestRunner报告模块使用及优化

    引言 在做接口自动化测试的时候,使用python单元测试框架unittest下HTMLTestRunner报告模板,可以很好的展示我们测试结果的数据. 官方的标准版模板地址:http://tungwa ...

  5. unittest ,ddt数据驱动,读取文件中数据,多个参数时的处理

    1. test.yaml中的数据 这里的属性是list 2.创建用例 3,在yaml中创建数据,创建list数据,list中再创建dict数据,这样就可以读取dict中的多个参数的数据了

  6. [ddt01篇]十年测试老鸟帮您解析:ddt数据驱动实现自动化测试入门基础应用

    一.什么是DDT数据驱动框架 ​ 全称:data driver test数据驱动测试框架,可以完美的应用于unittest框架实现数据驱动.ddt使用简介: 1.测试数据为多个字典的list类型 2. ...

  7. 单元测试unittest(基于数据驱动的框架:unittest+HTMLTestRunner/BeautifulReport+yaml+ddt)

    一.定义 unittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果 ...

  8. 基于Python的接口自动化-unittest测试框架和ddt数据驱动

    引言 在编写接口自动化用例时,我们一般针对一个接口建立一个.py文件,一条接口测试用例封装为一个函数(方法),但是在批量执行的过程中,如果其中一条出错,后面的用例就无法执行,还有在运行大量的接口测试用 ...

  9. Python&Selenium 数据驱动【unittest+ddt+json+HTMLTestRunner】

    一.摘要 本博文将介绍Python和Selenium做自动化测试的时候,基于unittest框架,借助ddt模块使用json文件作为数据文件作为测试输入,最后借助著名的HTMLTestRunner.p ...

随机推荐

  1. Vue学习笔记三:v-bind,v-on的使用

    目录 v-bind:绑定属性值,内容相当于js,缩写: v-on:绑定方法,缩写@ 总结 v-bind:绑定属性值,内容相当于js,缩写: 我添加了一个input标签,如下 <input typ ...

  2. FPGA

    FPGA(Field-Programmable Gate Array),即现场可编程门阵列,它是在PAL.GAL.CPLD等可编程器件的基础上进一步发展的产物.它是作为专用集成电路(ASIC)领域中的 ...

  3. Ubuntu 18.04 记录

    登录后死机,关机时死机的解决方法 更新内核并安装 Nvidia 显卡驱动可解决. 在内核更新为 4.15.18,Nvidia 显卡驱动为 390 时,问题解决. 使用 LiveCD 启动,然后 mou ...

  4. 根据ul的class和li的class获取li的value值

    <ul class="bd exam" style="display: none;"> <li class="cwhite acti ...

  5. Python简单试题

    1,相乘次数 题目要求描述: 一个整数每一位上的数字相乘,判断是否为个位数,若是则程序结束 ,不是则继续相乘,要求返回相乘次数. 例:39 > 3*9=27 > 2*7=14 > 1 ...

  6. Non-decreasing Array

    Given an array with n integers, your task is to check if it could become non-decreasing by modifying ...

  7. OSG开源教程(转)

    例:geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); 来指定要利用这些数据生成一个怎么样的形状. ...

  8. sublime text3输出窗口中文显示乱码问题解决方案

    1 前言 略 2 方案 修改Python3.sublime-build内容为 { "cmd": ["C:/Users/Administrator/AppData/Loca ...

  9. git 命令笔记

    切换 git 远程仓库HEAD分支 $ git remote set-head origin some_branch

  10. a标签锚点平滑跳转

    一.创建锚点 <div class="header" id="top">//终点标签,添加一个id <a href="#top&qu ...