【接口自动化】Python+Requests接口自动化测试框架搭建【三】

经过上两篇文章的讲解,我们已经完成接口自动化的基础框架,现在开始根据实际项目丰满起来。

在PyCharm中新建项目,项目工程结构如下:

 config:配置文件夹,可以将一些全局变量放于配置文件中,方便调用。例如:URL地址、端口,开发如经常更换端口在配置文件中便可修改。

data:测试用例表格文件夹,存放测试用例.xls和读取写入excel表的文件。

demo:程序公共类文件夹,存放程序公共类,例如:POST/GET请求,获取Token等。

kit:相关测试工具,压缩、发送邮件。

main:程序运行主文件夹。

report:测试报告文件夹。

test_case:测试用例。

 

公司实际开发项目中,存在接口依赖,即Token。Token获取方法为登录后返回Token值,所以我们编写一个登录类获取Token,并将Token放置于config文件中,成为全局变量,等其他接口调用时,直接引用变量。

在demo中新建DemoMain请求方法公共类。

DemoMain.py

#!/usr/bin/env python
# encoding: utf-8
'''
@author: GongYu
@license: (C) Copyright 2020
@contact: gong_yu_1996@163.com
@software: PyCharm
@file: DemoMain.py
@time: 2020/7/31 10:58
@desc: 公共方法主类
'''

import requests

class RunMain:
    def __init__(self):
        pass

    @staticmethod
    def send_post(url,cookies,headers,params=None):
        try:
            res = requests.post(url=url,cookies=cookies,headers=headers,data=params)
            return res.status_code # 返回响应状态代码
        except Exception as msg:
            return msg

    @staticmethod
    def send_get(url,cookies,headers,params=None,):
        try:
            res = requests.get(url=url,cookies=cookies,headers=headers,params=params,)
            return res.status_code  # 返回响应状态代码
        except Exception as msg:
            return msg

    def run_main(self, url,method,cookies=None,headers=None,params=None):
        if method == 'GET':
            res = self.send_get(url,cookies,headers,params)
            return res
        elif method == 'POST':
            res = self.send_post(url,cookies,headers,params)
            return res
        else:
            print('不支持的请求方式!')

CaseDemo.py 根据接口分开编写请求方法

实际开发中遇到的问题(仅为自己记录):

1.return返回值的问题:实际项目测试中我们不能只返回code状态码,因为接口测试中不能只凭返回状态码进行断言,我们测试判定中还应检查接口返回值,接口返回值应在开发提供接口文档已经注明。所以上述代码中我们应将返回值改为res。

2.因为一开始只考虑断言状态码的问题,所以导致多新建一个LoginDemo请求类,如返回值为res,此文件即可删除。

3.配置文件中可以参考Postman中多种参数的方式进行配置,可根据实际项目自己增加,极其方便。还可以配置数据库等信息,不再赘述。

 

data文件夹:

 

 GetExcel.py:获取测试用例操作类

#!/usr/bin/env python
# encoding: utf-8
'''
@author: GongYu
@license: (C) Copyright 2020
@contact: gong_yu_1996@163.com
@software: PyCharm
@file: GetExcel.py
@time: 2020/8/12 17:03
@desc:获取Excel表格数据
'''
import xlrd
def get_excel_data(sheetName,idCol=0,bodyCol=7,repsCol=9): # 获取数据函数
    dataList = [] # 生成一个空字典
    workSheet = xlrd.open_workbook('../data/JDData.xls', formatting_info=True).sheet_by_name(sheetName) # 获取表格
    endRow = workSheet.nrows # 获取有效工作行数
    for one in range(1, endRow): # 循环获取
        if workSheet.cell(one,12).value == 'Yes': # 判断用例是否执行
            dataList.append((workSheet.cell(one, idCol).value,workSheet.cell(one, bodyCol).value, workSheet.cell(one, repsCol).value)) # 追加dataList
        else:
            pass
    return dataList

固定读取表格中的数据即:第1列,第8列,第10列数据,所以形参写死。

SetExcel.py:测试结果写入Excel表格

#!/usr/bin/env python
# encoding: utf-8
'''
@author: GongYu
@license: (C) Copyright 2020
@contact: gong_yu_1996@163.com
@software: PyCharm
@file: SetExcel.py
@time: 2020/8/14 17:01
@desc: 写入Excel
'''
import xlrd
import json
from xlutils import copy
class CSetExcel():
    def SetExcel(self,sheetName,infodata,one,Col=10):
        path = '../data/JDData.xls'
        workSheet = xlrd.open_workbook(path,formatting_info=True)
        New_workSheet = copy.copy(workSheet) # 复制表格
        New_Sheet = New_workSheet.get_sheet(sheetName) # 获取表格名
        New_Sheet.write(one,Col,json.dumps(infodata,ensure_ascii=False)) # 写入Excel
        New_workSheet.save(path) # 保存

此处坑:

1.New_Sheet.write(one,Col,json.dumps(infodata,ensure_ascii=False)) # 写入Excel

如不加ensure_ascii=False,写入Excel中中文会被转义unicode编码。json.dumps(infodata):接口返回值为字典类型(dict)转换成字符串类型写入excel。

2.执行方法前,记得关闭Excel表格。

Data.excel模板格式

 此处坑:(MD,我也不知道我为啥这么多坑踩.........心累啊,前人种树后人乘凉,我先填为敬。)

编号一列单元格格式为文本,不要设置成数值,设置成数值会被Python取出后变为1.0(浮点型),然后导致的结果就是SetExcel.py根据编号写入数据时,无法识别1.0单元格在哪里,出现错误。

 

kit文件夹:存放测试报告压缩工具类以及发送邮件类

 

 

 ZipTool.py 压缩文件工具类

#!/usr/bin/env python
# encoding: utf-8
'''
@author: GongYu
@license: (C) Copyright 2020
@contact: gong_yu_1996@163.com
@software: PyCharm
@file: ZipTool.py
@time: 2020/8/19 9:52
@desc: 压缩文件夹工具
'''
import os
import zipfile
import shutil
class FileZip():
    def File(self,source_dir, output_filename):# 打包目录为zip文件(未压缩)
        if os.path.exists('../report/Report.zip') == True : # 判断文件是否存在
            print("报告压缩文件存在!正在执行删除........")
            os.remove('../report/Report.zip') # 删除文件
            print("删除成功!正在执行打包操作........")
            zipf = zipfile.ZipFile(output_filename, 'w')
            pre_len = len(os.path.dirname(source_dir))
            for parent, dirnames, filenames in os.walk(source_dir):
                for filename in filenames:
                    pathfile = os.path.join(parent, filename)
                    arcname = pathfile[pre_len:].strip(os.path.sep)  # 相对路径
                    zipf.write(pathfile, arcname)
            zipf.close()
            shutil.move('../main/Report.zip', '../report') # 移动文件
            print('打包完成,正在发送报告......')
        else:
            print('正在执行打包操作......')
            zipf = zipfile.ZipFile(output_filename, 'w')
            pre_len = len(os.path.dirname(source_dir))
            for parent, dirnames, filenames in os.walk(source_dir):
                for filename in filenames:
                    pathfile = os.path.join(parent, filename)
                    arcname = pathfile[pre_len:].strip(os.path.sep)
                    zipf.write(pathfile, arcname)
            zipf.close()
            shutil.move('../main/Report.zip', '../report')
            print('打包完成,正在发送报告......')

EmailTool.py 发送邮件工具类

#!/usr/bin/env python
# encoding: utf-8
'''
@author: GongYu
@license: (C) Copyright 2020
@contact: gong_yu_1996@163.com
@software: PyCharm
@file: EmailTool.py
@time: 2020/8/19 9:53
@desc: 发送邮件工具
'''

import smtplib
import time
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
class SendEmail():
    def Email(slef):
        # 第三方 SMTP 服务
        mail_host = "smtp.163.com"  # 设置服务器
        mail_user = "gong_yu_1996@163.com"  # 用户名
        mail_pass = " "  # 口令

        sender = 'gong_yu_1996@163.com'
        receivers = ['gong_yu_1996@163.com','1196936134@qq.com']  # 接收邮件,可设置为你的QQ邮箱或者其他邮箱,多邮箱设置为数组

        message = MIMEMultipart() 
        message['From'] = Header("GongYu", 'utf-8')
        #message['To'] = Header("测试", 'utf-8')
        ReportTime = time.strftime("%Y-%m-%d %H:%M") 
        subject = '['+ReportTime +']接口自动化测试报告'
        message['Subject'] = Header(subject, 'utf-8')

        # 邮件正文内容
        NewTime = time.strftime("%Y-%m-%d %H:%M")
        message.attach(MIMEText('各位领导,同事:附件内容为接口自动化测试报告。测试时间为:'+NewTime+',请下载查看!', 'plain', 'utf-8'))
        # 附件
        att1 = MIMEText(open('../data/Data.xls', 'rb').read(), 'base64', 'utf-8')
        att1["Content-Type"] = 'application/octet-stream'
        att1["Content-Disposition"] = 'attachment; filename="JDData.xls"'
        message.attach(att1)

        att2 = MIMEText(open('../report/Report.zip', 'rb').read(), 'base64', 'utf-8')
        att2["Content-Type"] = 'application/octet-stream'
        att2["Content-Disposition"] = 'attachment; filename="Report.zip"'
        message.attach(att2)

        try:
            smtpObj = smtplib.SMTP()
            smtpObj.connect(mail_host, 25)  # 25 为 SMTP 端口号
            smtpObj.login(mail_user, mail_pass)
            smtpObj.sendmail(sender, receivers, message.as_string())
            print("邮件发送成功!")
        except smtplib.SMTPException:
            print("Error: 无法发送邮件")

 下面我们编写Test_case.py 文件,放置于test_case文件夹下

Test_case.py

#!/usr/bin/env python
# encoding: utf-8
'''
@author: GongYu
@license: (C) Copyright 2020
@contact: gong_yu_1996@163.com
@software: PyCharm
@file: Test_test.py
@time: 2020/8/13 9:25
@desc: 测试执行
'''
import json
import pytest
import allure
from data.GetExcel import get_excel_data
from data.SetExcel import CSetExcel
from demo.CaseDemo import addapi


@allure.feature('地址接口测试')
class Testaddapi():

    @allure.story('获取一级地址')
    @pytest.mark.parametrize('idData,infoData,resultdata',get_excel_data('1-获取一级地址'))
    def test_getProvince(self,idData,infoData,resultdata):
        Res = addapi().getProvince()
        CSetExcel().SetExcel('1-获取一级地址', Res.json(), json.loads(idData))
        assert Res.status_code == 200
        assert Res.json()['resultMessage'] == json.loads(resultdata)['resultMessage']
        assert Res.json()['success'] == json.loads(resultdata)['success']

我们采用的是Pytest测试框架,使用allure输出测试报告。

到这里我们的测试框架就已经完成了,下面我们编写一个运行主类:TestMain.py 进行启动测试。

#!/usr/bin/env python
# encoding: utf-8
'''
@author: GongYu
@license: (C) Copyright 2020
@contact: gong_yu_1996@163.com
@software: PyCharm
@file: TestMain.py
@time: 2020/8/13 10:32
@desc: 运行主类
'''
import shutil
import pytest
import os
from kit.ZipTool import FileZip
from kit.EmailTool import SendEmail

if __name__ == '__main__':  # 启动allure
    if os.path.exists('../report/xml') == True or os.path.exists('../report/html') == True:
        print("报告目录存在!正在执行删除........")
        shutil.rmtree(r'../report/xml')
        shutil.rmtree(r'../report/html')
        print("删除成功!正在执行测试用例........")
        pytest.main(['../test_case/Test_test.py', '-s', '--alluredir', '../report/xml'])  # 生成测试报告文件
        print('测试报告转换HTML.....')
        os.system('allure generate ../report/xml -o ../report/html')  # 将测试报告文件转化为HTML
        FileZip().File('../report', 'Report.zip')
        SendEmail().Email()
        os.system('allure serve ../report/xml')  # 运行测试报告文件
    else:
        print('正在执行测试用例........')
        pytest.main(['../test_case/Test_test.py', '-s', '--alluredir', '../report/xml'])
        print('测试报告转换HTML.....')
        os.system('allure generate ../report/xml -o ../report/html')
        FileZip().File('../report', 'Report.zip')
        SendEmail().Email()
        os.system('allure serve ../report/xml')

下面我们运行试一下:

控制台输出:

 

 Allure测试报告:

 

 下面我们登录一下邮箱查看一下:

 

 我们已经将测试结果加入附件发送到了负责人的邮箱,到此我们的自动化测试框架已经完成。最后还有一个日志功能还没实现,等找个时间再来补充吧。

新手上路,知识不足,如有纰漏错误,还请大神们指正,谢谢各位咯~~~

 

posted on 2020-08-21 10:48  皮特宇  阅读(478)  评论(0)    收藏  举报