python接口自动化测试 订阅
Python接口自动化测试是2019年电子工业出版社出版的图书。作者是王浩然。 展开全文
Python接口自动化测试是2019年电子工业出版社出版的图书。作者是王浩然。
信息
页    数
232页
作    者
王浩然
定    价
¥59.0
字    数
230千字
书    名
Python接口自动化测试
出版时间
2019-5
开    本
16开
出版社
电子工业出版社
ISBN
9787121356872
Python接口自动化测试内容简介
本书主要介绍如何用Python实现接口自动化测试。全书主要内容包括接口基础、接口手工测试、编程前的准备、用Python处理MySQL数据库、用Python发送HTTP请求、用Python处理HTTP返回包、用Python导出测试数据、接口自动化起航及实际接口场景演示。本书所介绍的方法是作者在实际项目中实践过的,拥有这本书,就拥有了整套的源码。按照本书的环境设置,整套源码是完全可运行的。本书适合初、中级测试工程师,对Python语言感兴趣的人员,以及想要提升技术、突破技术的人员。 [1] 
收起全文
精华内容
下载资源
问答
  • python接口自动化测试

    2018-09-21 11:07:01
    python接口自动化测试教程,主要内容如下:基本原理,网络接口,json处理,网络请求,自动化
  • python接口自动化测试二:python代码实现接口测试

    url = ‘接口地址‘

    r = requests.get(url) #发送get请求

    print(r.status_code) #打印状态码,若有重定向,返回的是重定向之后的代码

    print(r.headers) #打印返回的报头(头部)

    print(r.text) #查看返回结果的文本形式

    r.status_code #响应状态码

    r.content #字节方式的响应体,会自动为你解码 gzip 和 deflate 压缩

    r.headers #以字典对象存储服务器响应头,但是这个字典比较特殊,字典键不区分大小写,若键不存在则返回None

    r.json() #Requests中内置的JSON解码器 ,json转成python的字典了

    r.url # 如果没有重定向,就是请求的url,如果有重定向,就是重定向后的url

    r.encoding # 查看返回的编码格式

    r.cookies # 获取cookie

    r.raw #返回原始响应体

    r.history #追踪重定向过程(list类型)

    r.text #字符串方式的响应体,会自动根据响应头部的字符编码进行解码

    r.content.decode(‘utf-8‘) # 返回内容有乱码时,用此方法打印

    r.raise_for_status() #失败请求(非200响应)抛出异常

    loginCookies = r.cookies: # 获取登录的cookies

    cookies=loginCookies: # 把获取到的cookies传入请求

    s = requests.session() # 可以理解为代码的微型浏览器,这样做的好处就是可以保存cookies,不用每次都去获取(只适用于网站是cookies这种,网站是token的没用)

    print(r.encoding) # 查看返回的编码格式

    r.json # 获取返回的json

    verify=False # 访问https请求时加上后不验证证书

    # open打开excel文件,保存为后缀为xls的文件

    fp = open(‘yoyo.xls‘, ‘wb‘) # w:写入, b:二进制的形式

    去掉Warning警告:

    import urllib3

    urllib3.disable_warnings()

    一、HTTP:

    get请求:

    1、get请求(无参数):

    2、get请求(带参数):

    接口地址:http://japi.juhe.cn/qqevaluate/qq

    返回格式:json

    请求方式:get post

    请求示例:http://japi.juhe.cn/qqevaluate/qq?key=您申请的appKey&qq=295424589

    接口备注:根据传入的参数 qq 号码和您申请的 appKey 测试 qq 的吉凶

    请求参数说明(入参) :

    名称 必填 类型 说明

    key 是 string 您申请的 appKey:8dbee1fcd8627fb6699bce7b986adc45

    qq 是 string 需要测试的 QQ 号码:907728701

    2.1、以url的方式传参:

    url = ‘http://japi.juhe.cn/qqevaluate/qq?key= 8dbee1fcd8627fb6699bce7b986adc45&qq=907728701‘

    2.2、以字典的形式传参:

    url = ‘http://japi.juhe.cn/qqevaluate/qq‘

    par = {

    ‘key‘:‘ 8dbee1fcd8627fb6699bce7b986adc45‘,

    ‘qq‘:‘907728701‘

    }

    r = requests.get(url,params=par) #发送get请求

    Post请求:

    1、 post请求(无参数):

    url = ‘http://japi.juhe.cn/qqevaluate/qq‘

    r = requests.post(url) #发送post请求

    print(r.status_code) #打印状态码

    print(r.headers) #打印返回的报头(头部)

    print(r.text) #查看返回结果的文本形式(body部分)

    2、 post请求(有参数):

    2.1、以url的方式传参:

    url = ‘http://japi.juhe.cn/qqevaluate/qq?key= 8dbee1fcd8627fb6699bce7b986adc45&qq=907728701‘

    r = requests.post(url) #发送post请求

    2.2、以字典的形式传参:

    url = ‘http://japi.juhe.cn/qqevaluate/qq‘

    par = {

    ‘key‘:‘8dbee1fcd8627fb6699bce7b986adc45‘,

    ‘qq‘:‘907728701‘

    }

    r = requests.post(url,params=par) #发送get请求

    二、HTTPS:

    1、get:

    url = ‘https://www.juhe.cn/docs/api/id/39‘

    r = requests.get(url) #发送get请求

    print(r.status_code) #打印状态码

    print(r.headers) #打印返回的报头(头部)

    print(r.text) #查看返回结果的文本形式(body部分)

    SSLError:证书问题:

    方法1.检查faddler是否关闭,关闭后,访问成功:

    方法2.请求参数后加上:verify=False

    verify默认为True,此时会验证证书,改为False将不会验证证书

    有Body部分:

    Content-Type: application/x-www-form-urlencoded; charset=UTF-8:传data

    Content-Type: application/json:传json

    把返回的内容解析为json格式:

    前提:一定内容为json格式

    若乱码::

    以content字节流输出,解码成utf-8:

    print(r.encoding) # 查看返回的编码格式:

    去掉Warning警告:

    import urllib3

    urllib3.disable_warnings()

    错误处理:

    403:拒绝或者禁止访问:须伪装头部(头部详情根据接口文档)

    1、服务器识别出为代码访问:

    1.1.代码访问的头部:User-Agent为python

    1.2.浏览器访问的头部:User-Agent为浏览器

    1.3.在头部加上User-Agent:

    2、伪装头部后仍然403:服务器校验Cookic (Cookic有时效性)

    2.1.代码访问时没有加Cookic

    2.2.浏览器访问时有Cookic

    2.3.在头部加上Cookic访问成功

    原文:https://www.cnblogs.com/zhongyehai/p/9159282.html

    展开全文
  • python 接口自动化测试python 接口自动化测试python 接口自动化测试python 接口自动化测试python 接口自动化测试python 接口自动化测试python 接口自动化测试python 接口自动化测试python 接口自动化测试python 接口...
  • 2019 Python接口自动化测试框架实战开发(一)

    万次阅读 多人点赞 2019-06-28 15:55:25
    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!...整个项目分为四个部分:接口基础丶接口开发丶Unittest与接口测试结合以及接口自动化框架从设计到开发 接口基础包括:H...

    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!

    项目源码下载

    目录

    一丶叙述

    二丶接口基础知识

    三丶接口测试工具

    四丶Fiddler的使用

    五丶unittest使用

    六丶mock服务入门到实战

    七丶接口自动化框架设计到开发


    一丶叙述

    1.项目介绍

    整个项目分为四个部分:接口基础丶接口开发丶Unittest与接口测试结合以及接口自动化框架从设计到开发

    接口基础包括:HTTP接口 / 常见接口 / 接口工具 / 接口基础知识

    接口开发:通过Django来开发get/post接口

    Unittest与接口测试结合:unittest应用 / 断言 / requests引入 / HTMLTestRunner / case的管理

    接口自动化框架从设计到开发:如何设计框架 / 封装工具类 / 重构基类 / 错误调试 / 结果收集以及处理 / 解决数据依赖 / 结果统计及报告发送

    项目整体思路:通过对接口数据文档的读写操作,来获取文档中case的所有数据,然后通过requests模块来发送请求获取的响应数据,通过返回的响应数据中的某个标志性字段的值来判断是否测试成功或者失败,最后将测试的结果数据写入到测试文档或者是html页面又或者是将结果以邮件的形式发送到指定邮箱,这是整个大框架思路,要完成这一系列自动化的测试框架,则需要有一定的python代码基础,博主这里只是粗略的叙述了思路,有很多地方就不细说了比如数据依赖等就请大家慢慢的阅读吧

    2.测试报告效果预览

    • unittest和HTMLTestRunner结合生成报告(新版本的)

    •  unittest和HTMLTestRunner结合生成报告(经典版本的)

    •  测试报告邮件通知

    二丶接口基础知识

    1.什么是接口

    连接前后端以及移动端,通俗来说就是前端和后端之间的桥梁,比如网站需要去调用银行丶微信及支付宝的接口来完成业务需求

    2.接口的种类

    外部接口和内部接口;内部接口又分为上层服务与下层服务以及同级服务

    3.接口的分类

    请求方式:post丶get丶delete丶put

    4.为什么要做接口测试

    原因:不同端的工作进度肯定是不一致的,那么就需要对最开始开发出来的接口进行测试;对于项目来说缩短项目周期,提高开发效率以及提高系统的健壮性

    5.接口测试流程

    需求讨论——需求评审——场景设计——用例设计——数据准备——执行

    6.为什么要设计测试用例

    • 理清思路,避免侧漏
    • 提高测试效率
    • 跟进测试进度
    • 告诉领导做过
    • 跟进重复重复性工作

    7.用例设计分类

    功能用例测试:测试功能是否正常丶测试功能是否按照接口文档实现

    逻辑用例设计:是否存在依赖业务,例如有些操作是需要用户登录成功的状态下才能进行的操作

    异常测试用例设计:参数异常以及数据异常;参数异常包括关键字参数丶参数为空丶多参数丶少参数丶错误参数,数据异常包括关键字数据丶数据为空丶长度不一致丶错误数据

    安全测试用例设计:cookie丶header丶唯一识别码

    三丶接口测试工具

    1.接口测试工具分类

    • 抓取接口工具

    httpwatch:集成于IE和Firefox浏览器中,在其他浏览器中无法使用,查看数据也比较麻烦

    wireshark:只要是经过电脑的所有请求都会去抓取,导致数据量比较庞大,看数据也比较麻烦

    fiddler:轻量级抓包工具,功能比较全,只会记录http请求不会像wireshark工具记录tcp和udp等请求

    • 测试接口工具:

    loadrunner:不仅仅是性能测试工具,由于该工具几乎都是基于http请求,所以也可以用来测试接口

    fiddler:它除了可以抓包还可以向接口发送各种请求

    soapui:接口和自动化测试工具,功能也比较强大

    jmeter:跟loadrunner一样不仅仅是做性能测试,也可以对接口进行测试

    postman:谷歌旗下的接口测试工具

    四丶Fiddler的使用

    1.抓取不同类型接口数据(http以及https)

    • 查看windows本机的IP

    • 配置fiddler

    • 需要保证要抓取的手机与电脑保持同一网段,博主这里使用逍遥模拟器模拟安卓手机,修改手机网络

    • 在高级选项中设置手动代理IP为windows本机IP地址,端口设置与fiddler抓取端口保持一致

    • 再安卓手机中打开知乎app,抓取知乎app的http服务的数据

    • 现在的移动app都是基于https请求的,所以需要在fiddler中设置https请求

    • 然后在手机端浏览器中访问windows电脑IP+port,进行网络安全证书的下载安装

    • 点击下面一个下载证书

    • 然后设置密码即可

    • 证书安装成功后,重新打开知乎app,则成功抓取https请求的数据

    • 在知乎app中随便对一文章进行评论,抓取该app评论接口

    2.数据模拟以及过滤规则

    • 如下图进行选择要过滤的hosts类型,并在输入框添加要过滤的hosts即可

    • 对知乎上的一篇文章进行回答后,获取https://api.zhihu.com/answers接口,查看发送的post请求数据中的content字段内容也就是博主回答的内容

    • 然后进行数据模拟,也就是点击fiddler软件上的replay对https://api.zhihu.com/answers接口进行post请求数据的而二次发送,由于知乎这边设定对一个问题只能进行一次回答,所以知乎服务器返回的json数据提示我们失败,同时也说明对接口进行二次数据发送成功,只是规则逻辑失败

    3.如何模拟接口响应数据

    • 首先第一步,访问知乎app热榜,在fiddler软件中获取接口查看服务器响应的json格式数据,从服务器返回的json数据看出热榜标题字段名为title_area

    • 然后选择服务器返回的数据类型为TextView,点击.View in Notepad即打开数据记事本,如下图在记事本中找到title_area字段的内容,该字段内容进行了将中文转换为一串字符串

    • 将记事本中的title_area字段的数据修改为this is a test for cdtaogang

    • 点击文件——另存为保存到桌面 

    • 回到fiddler中,左侧选中热榜接口,右侧选中AutoResponder,在此窗口下点击Add Rule将左侧的接口添加进去,在右侧下方导入保存在桌面的zhihu_hot.htm文件,最后点击sava保存

    • 回到知乎app中刷新当前热榜页面,则成功返回修改的热榜标题

    4.使用fiddler进行评论接口测试

    • 对一篇文章进行评论,抓取评论接口,因为get请求的接口测试太简单,所以博主这里选择评论接口即POST请求方式

    • 右击评论接口选择copy复制接口的url地址

    • 右侧选择Composer,将复制的评论接口url粘贴到地址栏,并选择POST请求方式

    • 因为评论接口涉及到用户身份验证也就是登录后才能进行评论的,所以需要将comments接口中request headers请求头中的所有请求数据以及请求数据中的TextView的值进行复制

    请求头数据

    请求体数据

    • 将上面复制的请求头和请求体数据分别粘贴到如下输入框中,点击Execute执行发送,然后在左侧则出现了另一个comments接口数据

    • 查看该comments接口,服务器返回的响应数据中与第一个comments接口一致,说明接口测试成功

    五丶unittest使用

    1.unittest简单使用

    • 在IDE中使用python的环境随便创建个py文件,需要注意的是该py文件的名字不能是test.py,否在运行时会出错,unittest包是python自带的不需要下载安装,代码如下
    # -*- coding: utf-8 -*-
    __author__ = 'cdtaogang'
    __date__ = '2019/6/17 13:10'
    
    import unittest
    
    
    class TestMethod(unittest.TestCase):
    
        @classmethod
        def setUpClass(cls):
            print("Method before class execution")
    
        @classmethod
        def tearDownClass(cls):
            print("Method after class execution")
    
        def setUp(self):
            print("------setUp------")
    
        def tearDown(self):
            print("------tearDown------")
    
        def test_01(self):
            print("First test method")
    
        def test_02(self):
            print("The second test method")
    
    
    if __name__ == '__main__':
        unittest.main()
    • 直接run运行以上代码

    2.unittest和request重构封装

    说明:使用requests模块对接口url地址发送请求,通过unittest测试框架进行case测试

    • 首先博主在逍遥安卓模拟器中下载了一个看书app,通过fiddler对app上的某一接口进行获取,之所以选择对此app进行接口测试,是因为该app的所有接口全是POST请求

    • 在PyCharm下新建工程目录,目录下创建base包,在包下创建一个demo.py文件以及test_method.py文件,用于使用unittest框架来测试以上app接口

    • 在demo.py文件中,使用requests get以及post方法进行了封装,主要是根据传递的参数method来对get以及post方法进行分别调用而已,具体实现如下
    import requests
    
    
    class RunMain:
    	def send_get(self,url,data):
    		res = requests.get(url=url,data=data).json()
    		return res
    		
    	def send_post(self,url,data):
    		res = requests.post(url=url,data=data).json()
    		return res
    
    	def run_main(self,url,method,data=None):
    		res = None
    		if method == 'GET':
    			res = self.send_get(url,data)
    		else:
    			res = self.send_post(url,data)
    		return res
    • 在test_method.py文件中则创建测试类以及test方法,在test方法中调用demo.py中的run_main方法,即使用requests模块向传递的接口url地址和请求方式以及请求体发送对应的请求,这里使用setUp方法则是利用其优先调用而对RunMain类进行实例化
    import unittest
    import json
    import HtmlTestRunner
    from .demo import RunMain
    
    
    class TestMethod(unittest.TestCase):
        def setUp(self):
            self.run = RunMain()
    
        def test_01(self):
            url = 'http://api.ishugui.com/asg/portal/call/265.do'
            data = {
                "sstoken":"eyJleHAiOjE1Njg1MzgyNTczMzUsImlhdCI6MTU2MDc2MjI1NzMzNSwicHAiOiIxMTQwNTQ1Njg5MDYwMDQ0ODAwQHNvaHUuY29tIiwidGsiOiIwZkNYSHpjTUZzR0dFMEswbVdvUVFCNWVCanpXa0hmWiIsInYiOjB9.SDYkT9FpWrBbko6xRrESN74IXJhzkqQLtijKjGiVrqA",
                "gidinf":"x011060802ff0fd40695d68140002799751474c540b3",
                "ppinf":"2|1560762257|1561971857|bG9naW5pZDowOnx1c2VyaWQ6Mjg6MTE0MDU0NTY4OTA2MDA0NDgwMEBzb2h1LmNvbXxzZXJ2aWNldXNlOjMwOjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMHxjcnQ6MTA6MjAxOS0wNi0xN3xlbXQ6MTowfGFwcGlkOjY6MTEwNjA4fHRydXN0OjE6MXxwYXJ0bmVyaWQ6MTowfHJlbGF0aW9uOjA6fHV1aWQ6MTY6czk1YWIwNDk5NjE3YmJhNnx1aWQ6MTY6czk1YWIwNDk5NjE3YmJhNnx1bmlxbmFtZTowOnw",
                "pprdig":"kaKPdU0WwIdzL58CqxNz5pgMyv23P0-Y5GRnd5ufPlXIGzrk7_7TlIK5XFQiuoqAHNqGVXHCVd4cB1DIkR5yFZ_nExnSjIZbBJWYlMkrsiIjDYqWCvedZRLm8sZqS0WqA0FcKXuSn3Z0gVRus9YpEonNz5wyuWdUqxaSmzlzygY",
                "ppsmu":"1|1560762257|1561971857|dXNlcmlkOjI4OjExNDA1NDU2ODkwNjAwNDQ4MDBAc29odS5jb218dWlkOjA6fHV1aWQ6MDo|byWcaoPqy02s2_9GHLhZFAQ6Ov_GazMPFLrq115HiSTBS9Ijr33a55quRq2Mr1_6ZMruKEk-BYFpShUaMtwRYA"
            }
            res1 = self.run.run_main(url, "POST", json.dumps(data))
            print(res1)
    
    
        def test_02(self):
            url = 'http://api.ishugui.com/asg/portal/call/265.do'
            data = {
    
            }
            res2 = self.run.run_main(url, 'POST', data)
    
            print(res2)
    
    
    if __name__ == '__main__':
        unittest.main()
    • 运行test_method模块,查看测试接口,test_02则是错误测试

    3.unittest中assert的使用

    • 首先根据返回的结果字典dict数据中的status状态值来判断测试是否通过或者失败,逻辑很基础就不细说了
    class TestMethod(unittest.TestCase):
        def setUp(self):
            self.run = RunMain()
    
        def test_01(self):
            url = 'http://api.ishugui.com/asg/portal/call/265.do'
            data = {
                "sstoken":"eyJleHAiOjE1Njg1MzgyNTczMzUsImlhdCI6MTU2MDc2MjI1NzMzNSwicHAiOiIxMTQwNTQ1Njg5MDYwMDQ0ODAwQHNvaHUuY29tIiwidGsiOiIwZkNYSHpjTUZzR0dFMEswbVdvUVFCNWVCanpXa0hmWiIsInYiOjB9.SDYkT9FpWrBbko6xRrESN74IXJhzkqQLtijKjGiVrqA",
                "gidinf":"x011060802ff0fd40695d68140002799751474c540b3",
                "ppinf":"2|1560762257|1561971857|bG9naW5pZDowOnx1c2VyaWQ6Mjg6MTE0MDU0NTY4OTA2MDA0NDgwMEBzb2h1LmNvbXxzZXJ2aWNldXNlOjMwOjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMHxjcnQ6MTA6MjAxOS0wNi0xN3xlbXQ6MTowfGFwcGlkOjY6MTEwNjA4fHRydXN0OjE6MXxwYXJ0bmVyaWQ6MTowfHJlbGF0aW9uOjA6fHV1aWQ6MTY6czk1YWIwNDk5NjE3YmJhNnx1aWQ6MTY6czk1YWIwNDk5NjE3YmJhNnx1bmlxbmFtZTowOnw",
                "pprdig":"kaKPdU0WwIdzL58CqxNz5pgMyv23P0-Y5GRnd5ufPlXIGzrk7_7TlIK5XFQiuoqAHNqGVXHCVd4cB1DIkR5yFZ_nExnSjIZbBJWYlMkrsiIjDYqWCvedZRLm8sZqS0WqA0FcKXuSn3Z0gVRus9YpEonNz5wyuWdUqxaSmzlzygY",
                "ppsmu":"1|1560762257|1561971857|dXNlcmlkOjI4OjExNDA1NDU2ODkwNjAwNDQ4MDBAc29odS5jb218dWlkOjA6fHV1aWQ6MDo|byWcaoPqy02s2_9GHLhZFAQ6Ov_GazMPFLrq115HiSTBS9Ijr33a55quRq2Mr1_6ZMruKEk-BYFpShUaMtwRYA"
            }
            res1 = self.run.run_main(url, "POST", json.dumps(data))
            # print(type(res1))
            # print(res1['pub'])
            # print(type(res1['pub']))
            if res1['pub']['status'] == 0:
                print("测试通过")
            else:
                print("测试失败")
            print(res1)
    
    
        def test_02(self):
            url = 'http://api.ishugui.com/asg/portal/call/265.do'
            data = {
    
            }
            res2 = self.run.run_main(url, 'POST', data)
            if res2['pub']['status'] == 0:
                print("测试通过")
            else:
                print("测试失败")
            print(res2)
    
    
    if __name__ == '__main__':
        unittest.main()
    • 运行以上代码,查看结果与预期一样

    • 将if判断代码更换成unittest模块中的assert断言进行判断,这里使用assertEqual方法来判断两个值是否相等,当两个值相等则返回OK,当不相同时返回assertEqual方法msg变量自定义的值
    class TestMethod(unittest.TestCase):
        def setUp(self):
            self.run = RunMain()
    
        def test_01(self):
            url = 'http://api.ishugui.com/asg/portal/call/265.do'
            data = {
                "sstoken":"eyJleHAiOjE1Njg1MzgyNTczMzUsImlhdCI6MTU2MDc2MjI1NzMzNSwicHAiOiIxMTQwNTQ1Njg5MDYwMDQ0ODAwQHNvaHUuY29tIiwidGsiOiIwZkNYSHpjTUZzR0dFMEswbVdvUVFCNWVCanpXa0hmWiIsInYiOjB9.SDYkT9FpWrBbko6xRrESN74IXJhzkqQLtijKjGiVrqA",
                "gidinf":"x011060802ff0fd40695d68140002799751474c540b3",
                "ppinf":"2|1560762257|1561971857|bG9naW5pZDowOnx1c2VyaWQ6Mjg6MTE0MDU0NTY4OTA2MDA0NDgwMEBzb2h1LmNvbXxzZXJ2aWNldXNlOjMwOjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMHxjcnQ6MTA6MjAxOS0wNi0xN3xlbXQ6MTowfGFwcGlkOjY6MTEwNjA4fHRydXN0OjE6MXxwYXJ0bmVyaWQ6MTowfHJlbGF0aW9uOjA6fHV1aWQ6MTY6czk1YWIwNDk5NjE3YmJhNnx1aWQ6MTY6czk1YWIwNDk5NjE3YmJhNnx1bmlxbmFtZTowOnw",
                "pprdig":"kaKPdU0WwIdzL58CqxNz5pgMyv23P0-Y5GRnd5ufPlXIGzrk7_7TlIK5XFQiuoqAHNqGVXHCVd4cB1DIkR5yFZ_nExnSjIZbBJWYlMkrsiIjDYqWCvedZRLm8sZqS0WqA0FcKXuSn3Z0gVRus9YpEonNz5wyuWdUqxaSmzlzygY",
                "ppsmu":"1|1560762257|1561971857|dXNlcmlkOjI4OjExNDA1NDU2ODkwNjAwNDQ4MDBAc29odS5jb218dWlkOjA6fHV1aWQ6MDo|byWcaoPqy02s2_9GHLhZFAQ6Ov_GazMPFLrq115HiSTBS9Ijr33a55quRq2Mr1_6ZMruKEk-BYFpShUaMtwRYA"
            }
            res1 = self.run.run_main(url, "POST", json.dumps(data))
            # print(type(res1))
            # print(res1['pub'])
            # print(type(res1['pub']))
            # if res1['pub']['status'] == 0:
            #     print("测试通过")
            # else:
            #     print("测试失败")
            self.assertEqual(res1['pub']['status'], 0, "测试失败")
            print(res1)
    
    
        def test_02(self):
            url = 'http://api.ishugui.com/asg/portal/call/265.do'
            data = {
    
            }
            res2 = self.run.run_main(url, 'POST', data)
            # if res2['pub']['status'] == 0:
            #     print("测试通过")
            # else:
            #     print("测试失败")
            self.assertEqual(res2['pub']['status'], 0, "测试失败")
            print(res2)
    
    
    if __name__ == '__main__':
        unittest.main()
    • 测试查看结果,断言失败,测试结果如下很清晰

    4.unittest中case的管理及运用

    • 在测试一些接口时,有些接口的返回数据需要在下一个接口进行使用,所以需要定义全局变量,方便每个case都能够得着,当在test_01中定义全局变量userid,然后在test_02中进行打印

    • 在unittest中,是按照字母数字来进行case先后执行顺序的,将test_01改为test_03后,运行代码后,会提示test_02中的userid未定义,原因是程序先去执行了test_02这个case,所以出现该提示是正常的

    • 当在测试代码中有很多case时,我想跳过某个case,则在该case方法上定义unittest的skip方法装饰器,并需要传递此方法名作为实参进行传递

    • 除了在if __name__ == '__main__'中使用unittest.main方法执行所有的case以外,还可以将要测试的case添加到unittest.TestSuite集合中执行想要执行的case,若想要全部都执行则需要一个一个的添加

    5.unittest和HTMLTestRunner结合生成报告(博主这里给大家展现两种)

    第一种:比较新版本的htmltestrunner报告

    • 然后将下载好的whl文件放在你的项目环境的Scripts目录下

    • 最后在Terminal终端或者cmd终端中进入以上目录,执行如下命令即可

    • 安装成功后,即在以下路径中可以找到安装的HTMLTestRunner的包了

    • 在if __name__ == '__main__'中只需要调用HtmlTestRunner模块中的HtmlTestRunner类,向该类传递报告标题参数值即可,其他均默认,需要注意的时启动文件run为当前的py文件,如果是Unittests开头的启动文件,则不会运行if __name__ == '__main__'下的代码,只会执行unittest框架的setUp以及test开头的case代码

    • 运行test_method.py文件,成功在base目录下创建reports目录,并在该目录下生成对应时间的测试报告

    • 打开reports目录下生成的html测试报告,查看测试内容,与预期设定一样,test_02失败test_03成功,说明一下报告中的乱码为中文

    第二种:比较经典版本的htmltestrunner报告

    • 为了方便演示效果,博主在testItems项目目录下,创建base2的模块,将base模块下的demo.py和test_method.py文件拷贝到base2目录下并将test_method.py命令为test_method2.py免得搞混淆,然后在base2目录下新建HTMLTestRunner.py文件用于存放其源码,目录结构如下

    第94行, 将import StringIO修改成import io
    第539行,将self.outputBuffer = StringIO.StringIO()修改成self.outputBuffer = io.StringIO()
    第642行,将if not rmap.has_key(cls):修改成if not cls in rmap:
    第631行,将print >> sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)修改成print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))
    第766行,将uo = o.decode('latin-1')修改成uo = e
    第775行,将ue = e.decode('latin-1')修改成ue = e
    • 在test_method2模块中首先需要从base2模块中去导入HTMLTestRunner文件,然后if __name__ == '__main__'中,需要创建一个文件源,同样是调用HTMLTestRunner模块中的HTMLTestRunner类,不同的是需要将创建的文件源传递给实例属性stream变量

    • 运行test_method2.py,成功在上一级report目录下生成html_report.html报告文件

    • 打开html_report.html测试报告,测试结果与代码设定一致

    六丶mock服务入门到实战

    1.mock简介

    mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法,mock是在测试过程中,对于一些不容易构造/获取的对象,创建一个mock对象来模拟对象的行为即就是模拟fiddler返回接口响应数据的一个过程。

    2.mock安装

    • 在终端使用pip进行安装即可

    3.在case中通过底层函数实现mock

    • 在test_method模块中导入mock,然后在test_03函数中通过以下代码设置返回的return_value的值为请求的data数据
    mock_data = mock.Mock(return_value=data)
    print(mock_data)
    • run运行Unittests in test_method.py,打印出Mock id的值

    • 将调用run_main方法的值设定为mock_data,即print(res1)则表示打印请求的data数据的值,因为res1的数据不再是接口返回的响应数据,则arrest断言是会提示报错的,这是正常的

    4.重构封装mock服务

    • 在base目录下创建mock_demo.py文件,构造一个mock_test方法,该方法就是将test_03方法中self.run.run_main = mock.Mock(return_value=data) 和 res1 = self.run.run_main(url, "POST", json.dumps(data))方法的调用进行了封装成为test_02和test_03方法通用的一个方法,上一步骤中的代码mock_data = mock.Mock(return_value=data) 和self.run.run_main = mock_data,即就相当于self.run.run_main = mock.Mock(return_value=data)而已,都是python基本的调用封装基础知识,mock_demo.py中的代码如下
    # -*- coding: utf-8 -*-
    __author__ = 'cdtaogang'
    __date__ = '2019/6/20 16:26'
    from mock import mock
    import json
    
    def mock_test(mock_method, request_data, url, method, response_data):
        """
        :param mock_method:
        :param request_data:
        :param url:
        :param method:
        :param response_data:
        :return: res
        """
        mock_method = mock.Mock(return_value=response_data)
        print('mock_method:', mock_method)
        res = mock_method(url, method, json.dumps(request_data))
        return res
    • 那么在test_03方法中,如下进行调用即可
    res1 = mock_test(self.run.run_main, data, url, 'POST', 'ssssssss')
    print('res1:', res1)
    • 运行Unittests in test_method.py,查看运行结果和博主设定一样成功返回自定义的response_data数据

    七丶接口自动化框架设计到开发

    1.如何设计一个接口自动化测试框架

    根据接口地址丶接口类型丶请求数据丶预期结果来进行设计,对于需要登录后才能进行操作的接口那么则需要进行header cookie等数据的传递,自动化测试的难点就是数据依赖。

    2.python操作excel获得内容

    • 首先python操作excel,需要安装两个包,分别是xlrd和xlwt这两个库,xlrd这个库是负责读取excel数据的,而xlwt库是负责向excel写入数据的

    • 在项目目录下创建utils工具包,在该包下创建op_excel.py文件,在该文件中通过导入xlrd包,对excel表的数据进行读取操作

    3.重构操作excel函数

    • 根据上一步骤读取excel表的内容代码后,进行了一个简单的封装,提高代码的通用性,过程相当的简单,实现代码如下
    # -*- coding: utf-8 -*-
    __author__ = 'cdtaogang'
    __date__ = '2019/6/20 17:33'
    import xlrd
    
    data = xlrd.open_workbook("../test_data/rs.xls")
    tables = data.sheets()[0]  # 获取表格数据对象
    print(tables.nrows) # 打印表格行数
    print(tables.cell_value(0,0))  # 打印excel表格数据,需要传递数据所在的坐标(x,y)
    print(tables.cell_value(0,1))
    print("*"*50+"封装前后数据对比"+"*"*50)
    
    
    class operationExcel(object):
        def __init__(self, file_path="../test_data/rs.xls", sheet_id=0):
            self.file_path = file_path
            self.sheet_id = sheet_id
            self.data = self.get_data()
    
        def get_data(self):
            data = xlrd.open_workbook(self.file_path)
            tables = data.sheets()[self.sheet_id]
            return tables
    
        def get_rows(self):
            """获取单元格的排数"""
            return self.data.nrows
    
        def get_cell_value(self, x=0, y=0):
            """获取某个单元格的数据"""
            return self.data.cell_value(x, y)
    
    
    if __name__ == '__main__':
        print(operationExcel().get_rows())
        print(operationExcel().get_cell_value())
        print(operationExcel().get_cell_value(0,1))
    • 运行op_excel.py文件后,结果与封装之前代码结果一致,表示重构封装代码成功

    4.学习操作json文件

    • 自定义一个登录的json文件名为login.json,文件内容如下,存放在test_data目录下

    • 在utils工具包下创建op_json.py文件,在文件中对login.json文件内容进行读取操作,代码如下

    5.重构json工具类

    • 将上一步操作json的代码进行封装
    class operationJson(object):
        def __init__(self, file_path="../test_data/login.json"):
            self.file_path = file_path
            self.data = self.get_data()
    
        def get_data(self):
            with open(self.file_path) as f:
                data = json.load(f)
                return data
    
        def get_key_words(self, key=None):
            if key:
                return self.data[key]
            else:
                return self.data
    
    
    if __name__ == '__main__':
        print(operationJson().get_key_words())
        print(operationJson().get_key_words("login"))
        print(operationJson().get_key_words("login")['username'])
    • 运行op_json.py文件,结果与封装之前代码结果一致,表示重构封装代码成功

    6.封装获取常量方法

    • 首先打开excel表格,查看需要获取的字段有哪些

    • 对excel表的字段进行获取,在项目目录下创建名为data的python包,在该包下创建data_conf.py,代码就是简单的获取对应的变量值,具体如下
    # -*- coding: utf-8 -*-
    __author__ = 'cdtaogang'
    __date__ = '2019/6/21 9:29'
    
    
    class global_var:
        id = '0'  # id
        module = '1'  # 模块
        url = '2'  # url
        run = '3'  # 是否运行
        request_type = '4'  # 请求类型
        request_header = '5'  # 是否携带header
        case_depend = '6'  # case依赖
        response_data_depend = '7'  # 依赖的返回数据
        data_depend = '8'  #  数据依赖
        request_data = '9'  # 请求数据
        expect_result = '10'  # 预期结果
        reality_result = '11'  # 实际结果
    
    
    def get_id():
        return global_var.id
    
    def get_module():
        return global_var.module
    
    def get_url():
        return global_var.url
    
    def get_run():
        return global_var.run
    
    def get_request_type():
        return global_var.request_type
    
    def get_request_header():
        return global_var.request_header
    
    def get_case_depend():
        return global_var.case_depend
    
    def get_response_data_depend():
        return global_var.response_data_depend
    
    def get_data_depend():
        return global_var.data_depend
    
    def get_request_data():
        return global_var.request_data
    
    def get_expect_result():
        return global_var.expect_result
    
    def get_reality_result():
        return global_var.reality_result

    7.封装获取接口数据

    • 在data目录下创建data_get.py文件,在该文件中对excel表数据以及json数据结合上一步封装的常量方法整合后的实现,代码如下
    # -*- coding: utf-8 -*-
    __author__ = 'cdtaogang'
    __date__ = '2019/6/21 10:01'
    from utils.op_excel import operationExcel
    from utils.op_json import operationJson
    from data import data_conf
    
    class getData(object):
        def __init__(self):
            self.op_excel = operationExcel()
    
        def get_case_lines(self):
            """获取表格行数"""
            return self.op_excel.get_rows()
    
        def get_is_run(self, x):
            """获取case是否运行"""
            flag = None
            y = data_conf.get_run()
            run_value = self.op_excel.get_cell_value(x, y)
            if run_value == 'yes':
                flag = True
            else:
                flag = False
            return flag
    
        def get_is_header(self, x):
            """是否携带header"""
            y = data_conf.get_request_header()
            header = self.op_excel.get_cell_value(x, y)
            if header == 'yes':
                return data_conf.get_header_value()
            else:
                return None
    
        def get_request_method(self, x):
            """获取请求方式"""
            y = data_conf.get_request_type()
            request_method = self.op_excel.get_cell_value(x, y)
            return request_method
    
        def get_request_url(self, x):
            """获取请求地址"""
            y = data_conf.get_url()
            request_url = self.op_excel.get_cell_value(x, y)
            return request_url
    
        def get_request_data(self, x):
            """获取请求数据"""
            y = data_conf.get_request_data()
            request_data = self.op_excel.get_cell_value(x, y)
            if request_data == '':
                return None
            return request_data
    
        def get_data_for_json(self, x):
            """通过excel中的关键字去获取json数据"""
            op_json = operationJson()
            data = op_json.get_key_words(self.get_request_data(x))
            return data
    
        def get_expect_data(self, x):
            """获取预期结果数据"""
            y = data_conf.get_expect_result()
            expect_data = self.op_excel.get_cell_value(x, y)
            if expect_data == '':
                return None
            return expect_data

    8.post、get基类的封装

    • 在base包下创建run_method.py文件,在文件中重新编写对get丶post请求方式的代码封装,具体如下
    # -*- coding: utf-8 -*-
    __author__ = 'cdtaogang'
    __date__ = '2019/6/21 11:19'
    import requests
    
    
    class RunMain(object):
    
        def get_main(self, url, data=None, header=None):
            res = None
            if header is not None:
                res = requests.get(url=url, data=data, headers=header).json()
            else:
                res = requests.get(url=url, data=data).json()
            return res
    
        def post_main(self, url, data, header=None):
            res = None
            if header is not None:
                res = requests.post(url=url, data=data, headers=header).json()
            else:
                res = requests.post(url=url, data=data).json()
            return res
    
    
        def run_main(self, url, method, data=None, header=None):
            res = None
            if method.lower() == 'post':
                res = self.post_main(url, data, header)
            elif method.lower() == 'get':
                res = self.get_main(url, data, header)
            else:
                return "what ?????"
            return res

    9.主流程封装及错误解决调试

    • 首先在testItems项目目录下新建一个名为main的python包,在该包下创建名为run_test的py文件,该文件为主程序启动文件,代码的逻辑就是将前面封装的方法进行了调用核心就是读取excel表的数据,通过读取到的数据,发送请求,其中包括某一些变量的判断,根据该判断然后到json数据中获取请求的数据,最后就这么的简单,代码如下
    # -*- coding: utf-8 -*-
    __author__ = 'cdtaogang'
    __date__ = '2019/6/21 11:57'
    from base.run_method import RunMain
    from data.data_get import getData
    
    
    class RunTest(object):
        def __init__(self):
            self.runmain = RunMain()
            self.data = getData()
    
        def run(self):
            res = None
            row_counts = self.data.get_case_lines()  # 获取excel表格行数
            # print(row_counts) 5
            for row_count in range(1, row_counts):
                # print(row_count) 1,2,3,4
                url = self.data.get_request_url(row_count)  # y行不变遍历获取x列的请求地址
                method = self.data.get_request_method(row_count)  # y行不变遍历获取x列的请求方式
                is_run = self.data.get_is_run(row_count)  # y行不变遍历获取x列的是否运行
                data = self.data.get_data_for_json(row_count)  # y行不变遍历获取x列的请求数据,这里面时三次调用,依次分别是get_data_for_json丶get_key_words丶get_request_data
                header = self.data.get_is_header(row_count)
                print('url:', url)
                print('method:', method)
                print('is_run:', is_run)
                print('data:', data)
                print('header:', header)
    
                if is_run:
                    res = self.runmain.run_main(url,method,data,header)
                    print("*"*60+"分割线"+"*"*60)
            return res
    
    
    if __name__ == '__main__':
        print('res:', RunTest().run())
    • 运行run_test,成功的将excel以及json数据正确打印出来,返回res服务器返回结果,需要说明的是excel表中的所有数据都不是真实存在的,包括json文档数据也是,这里主要是测试整个框架的正确性读取excel以及json文档数据,并正确的发送请求获得相应数据

    • 运行结果出现红色的内容,是由requests模块发送请求的安全请求警告,如不想显示此警告,可以在run_method.py发送请求核心代码进行禁用,禁用代码如下

    • 重新运行run_test,安全请求警告不再显示

    • 根据代码运行结果,对比excel表以及json数据文档内容,数据正确无误

    10. 返回数据格式处理以及调错

    • 为了测试返回的接口的响应数据,博主这里在excel文档以及json文档中添加了一条数据

    • 因为在excel文档中小说的接口不携带header所以在向接口发送请求数据核心代码块,进行了如下修改,因为在excel文档中的最后一个接口时真实的,所以只需要对最后一个接口url返回的字典类型的响应数据进行转换成json格式的数据,并按照关键字进行排序

    • 运行run_test,在最后一个接口中成功打印出我们想要的数据

    11.获取接口返回状态

    • 在发送请求数据核心代码中,进行打印返回的状态码status_code即可,最后一个接口比较特殊,返回的响应数据中没有status_code,所以需要对返回的json数据中的status进行判断,并向其返回数据中添加我们所要的status_code的值

    • 运行代码,当返回的状态码为404表示接口不存在,只要是存在响应数据,则status_code为200,必须说明一点的就是status_code为200不一定表示接口存在,有些大型网站会对其域名下不存在的接口返回200的错误页面显示,所以在测试文档中会体现预期结果和实际结果两项数据需要一致才能表示测试通过

    12.通过预期结果判断case是否执行成功

    • 进行接下来的测试,博主这里重新准备了另一个excel表来进行测试,需要对json文件中的数据进行添加,在excel表Book-05中的请求数据book5关键字对应的json文件的数据故意为空,可以对测试结果有一个对比

    • 在数据获取核心类中定义了一个方法来获取excel表模块字段的数据

    • 回过头在启动文件中获取模块名预期结果并进行打印

    • 运行启动文件,查看运行结果

    • 在utils目录下,创建common_util.py文件,在该文件代码中通过启动文件传递过来的数据来判断excel表预期结果数据的status状态码与res结果中的status状态码是否一致,一致表示测试通过,不一致则失败,代码如下
    # -*- coding: utf-8 -*-
    __author__ = 'cdtaogang'
    __date__ = '2019/6/21 18:43'
    import json
    
    class CommonUtil(object):
        def is_contains(self, expect, reality):
            flag = None
            reality = json.loads(reality)
            expect = json.loads(expect)
            if expect['status'] == reality['pub']['status']:
                flag = True
            else:
                flag = False
            return flag
    • 在启动文件中需要注释掉res响应数据,利于查看测试结果,还需要在启动文件调用is_contains方法来根据其返回值判断测试是否通过

    • 运行启动文件,查看测试结果

    13.将测试结果写入到excel中

    • 首先在op_excel.py中定义一个方法,该方法实现读取excel的数据,并进行copy复制,然后再write方法将数据写入到坐标位置

    • 然后在data_get.py中需要定义一个方法,在该方法中核心逻辑为获取y坐标的值

    • 最后在启动文件中,调用data_get模块中的write_reality_data方法,并将剩余的x坐标的值以及data数据传递给最终的核心方法write_reality_result_data来完成对excel表中的实际结果数据的写入

    • 将excel表进行关闭后,运行启动文件,再次打开excel表,实际结果数据写入正确,之所以需要关闭excel是避免提示提示错误,无法写入保存数据

     

    展开全文
  • Python接口自动化测试框架在自动化的测试体系中,包含了UI自动化测试和接口自动化测试,UI自动化实现的前提是软件版本进入稳定期,UI界面稳定、变动少,相比较之下接口自动化,接口受外界因素的影响较少,维护成本低...

    Python接口自动化测试框架

    在自动化的测试体系中,包含了UI自动化测试和接口自动化测试,UI自动化实现的前提是软件版本进入稳定期,UI界面稳定、变动少,相比较之下接口自动化,接口受外界因素的影响较少,维护成本低,能够在最短时间发现问题。

    一、浅谈接口测试

    1、什么是接口测试:

    API测试又称为接口测试,主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点,是对系统接口功能进行测试的一种手段,也是集成测试的一部分,通过直接控制被测应用的接口(API)来确定是否在功能、可靠性、性能和安全方面达到预期的软件测试活动。

    2、如何测试接口:

    检查接口返回的数据是否与预期结果一致。

    检查接口的容错性,假如传递数据的类型错误时是否可以处理。

    接口参数的边界值。例如,传递的参数足够大或为负数时,接口是否可以正常处理。

    接口的性能,http请求接口大多与后端代码逻辑、执行的SQL语句性能、算法等相关。

    接口的安全性,外部调用的接口尤为重要。

    3、接口测试的意义、目的:

    接口测试的核心意义、目的在于:以保证系统的正确和稳定为核心,以持续集成为手段,提高测试效率,提升用户体验,降低产品研发成本。

    二、定义框架目录分层

    接口自动化框架的没有统一标准,可以根据实际需要自定义,以满足功能测试目标要求为目的。一个基本的接口自动化测试框架需要满足的功能:测试用例管理、各种配置信息管理、数据库操作、日志打印、报告输出、邮件发送

    """API_Autotest/

    |-- API_Case/ #测试用例

    | | |-- PreviewRelease_01_RegisterLogin.py #预发布环境注册登录接口case

    | | |-- PreviewRelease_02_SubmitCredit.py #预发布环境主流程接口case

    | | |-- PreviewRelease_03_MobilePhonePWD.py #预发布环境.......接口case

    | | |-- Test_01_RegisterLogin.py #测试环境注册登录接口case

    | | |-- Test_02_SubmitCredit.py #测试环境主流程接口case

    | | |-- Test_03_LoanRepayment.py #测试环境......接口case

    | | |

    |-- data/ ###配置信息

    | |-- conf_dict.py #账号密码等配置信息

    | |-- custom_variable.py #向接口请求的请求的参数变量、keys、请求头

    | |-- export_url.py #接口url

    | |-- request_dict.py #向接口请求的请求参数

    |

    |-- logic/ ###主要逻辑

    | |-- export_logic.py #接口实现主逻辑

    | |-- database.py #数据库操作类

    | |-- log_print.py #日志打印类

    | |-- public_class.py #公用函数类

    | |-- send_email.py #发送邮件类

    |

    |-- log/ #日志

    | |-- Case--201804182020_log #根据运行日期保存操作日志

    | |-- Case--201804182022_log

    |

    |-- report/ #测试报告

    | |-- report--201804181729.html #根据运行日期保存测试报告日志

    | |-- report--201804181731.html

    |

    |-- readme.md #readme

    |

    |-- manage.py #接口case运行管理类"""

    三、知识技能储备

    萝卜青菜各有所爱,每个人心中的接口自动化测试框架也各不相同,想实现一个基础功能完备的接口测试框架需要的Python知识如下:

    1、Python基础知识

    列举了一些需要掌握的基础知识

    2、主要依赖的库

    下面介绍的库都是数据库操作、日志打印、报告输出、邮件发送功能实现所依赖的库:

    a、数据库操作

    数据库操作主要pymysql库,下面为代码示例:

    importpymysqlimportdatetime,timeimportosfrom data.conf_dict importConfDatafrom logic.log_print importLOGfrom logic.public_class importPublicclassConnectDatabase():"""连接数据库类"""

    def __init__(self):

    self.Log=LOG()

    self.conf_data=ConfData()#连接数据库110

    self.connection_110 = pymysql.connect(host=self.conf_data.get_conf_data("database_110", "host"),

    port=self.conf_data.get_conf_data("database_110", "port"),

    user=self.conf_data.get_conf_data("database_110", "user"),

    password=self.conf_data.get_conf_data("database_110", "password"),

    db=self.conf_data.get_conf_data("database_110", "db"),

    charset='utf8',#以字典形式展示所查询数据

    cursorclass=pymysql.cursors.DictCursor)#保存错误日志的文件名称

    self.log_name = Public.get_new_file(path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "log"))def select_sql(self, **kwargs):"""根据传入参数执行数据库查询操作

    :param args:

    :param kwargs: database:(database_110)选择数据库、table:表名、condition:where条件

    :return:"""database_name= kwargs.get("database")

    field_name= kwargs.get("field", "*")

    table_name= kwargs.get("table")

    where_condition= kwargs.get("condition")if database_name == "database_110":try:

    with self.connection_110.cursor() as cursor:

    sql= "SELECT %s FROM %s WHERE %s;"data=(field_name, table_name, where_condition)

    cursor.execute(sql%data)

    self.connection_110.commit()

    result=cursor.fetchone()returnresultexceptException as e:

    self.Log.log_warning("database", self.log_name, "select_error:%s" %e)def select_sql_all(self, *args, **kwargs):"""根据传入参数执行数据库查询操作

    :param args:

    :param kwargs: database:(database_110)选择数据库、table:表名、condition:where条件

    :return:"""database_name= kwargs.get("database")

    field_name= kwargs.get("field", "*")

    table_name= kwargs.get("table")

    where_condition= kwargs.get("condition")if database_name == "database_110":try:

    with self.connection_110.cursor() as cursor:

    sql= "SELECT %s FROM %s WHERE %s;"data=(field_name, table_name, where_condition)print((sql %data))

    cursor.execute(sql%data)

    self.connection_110.commit()

    result=cursor.fetchall()returnresultexceptException as e:

    self.Log.log_warning("database", self.log_name, "select_error:%s" %e)def update_sql(self, *args, **kwargs):"""根据传入参数执行数据库更新操作

    :param args:

    :param kwargs: database:(database_110)选择数据库、table:表名、set:更新的字段和值、condition:where条件

    :return:"""database_name= kwargs.get("database")

    table_name= kwargs.get("table")

    set_value= kwargs.get("set")

    where_condition= kwargs.get("condition")if database_name == "database_110":try:

    with self.connection_110.cursor() as cursor:

    sql= "UPDATE %s SET %s WHERE %s;"data=(table_name, set_value, where_condition)#print(sql%data)

    cursor.execute(sql %data)

    self.connection_110.commit()returncursor.rowcount

    cursor.close()exceptException as e:

    self.Log.log_warning("database", self.log_name, "update_error:%s" %e)

    self.connection_110.rollback()def delete_sql(self, *args, **kwargs):"""根据传入参数执行数据库删除操作

    :param args:

    :param kwargs: database:(database_110)选择数据库、table:表名、condition:where条件

    :return:"""database_name= kwargs.get("database")

    table_name= kwargs.get("table")

    where_condition= kwargs.get("condition")if database_name == "database_110":try:

    with self.connection_110.cursor() as cursor:

    sql= "DELETE from %s where %s;"data=(table_name, where_condition)

    cursor.execute(sql%data)

    self.connection_110.commit()returncursor.rowcountexceptException as e:

    self.Log.log_warning("database", self.log_name, "delete_error:%s" %e)

    self.connection_110.rollback()def insert_sql(self, *args, **kwargs):"""根据传入参数执行数据库插入操作

    :param args:

    :param kwargs: database:(database_110)选择数据库、sql:需要插入的sql语句

    :return:"""database_name= kwargs.get("database")

    insert_sql= kwargs.get("sql")if database_name == "database_110":try:

    with self.connection_110.cursor() as cursor:

    cursor.execute(insert_sql)

    self.connection_110.commit()returncursor.rowcountexceptException as e:

    self.Log.log_warning("database", self.log_name, "insert_error:%s" %e)

    self.connection_110.rollback()def mysql_function(self, *args, **kwargs):"""根据传入参数执行数据库函数操作

    :param args:

    :param kwargs: database:(database_110)选择数据库、function_name:函数名称,data_id:数据ID,phone:电话

    :return:"""database_name= kwargs.get("database")

    function_name= kwargs.get("function_name")

    data_id= kwargs.get("data_id")

    phone= kwargs.get("phone")

    product_id= kwargs.get("product_id")if database_name == "database_110":try:

    with self.connection_110.cursor() as cursor:

    cursor.callproc(function_name,args=(data_id,phone,product_id,))

    self.connection_110.commit()exceptException as e:

    self.Log.log_warning("database", self.log_name, "mysql_function:%s" %e)

    self.connection_110.rollback()if __name__ == "__main__":

    b=ConnectDatabase()

    data_id= Public.create_short_id()

    示例代码--删减版

    PS:pymsql库操作mysql数据库增、删、查、改、调用函数

    b、日志打印

    日志打印依赖logging库,下面为代码示例:

    importloggingimportosimportsysimportdatetime

    log_path= os.path.join(os.path.dirname(os.path.dirname(__file__)), "log")

    sys.path.append(log_path)classLOG(object):"""日志打印类"""

    def __init__(self):

    self.now_time= datetime.datetime.now().strftime("%Y%m%d%H%M")def log_info(self, *args):"""根据传入参数打印普通日志

    :param arg[0]log的功能模块名,arg[1] 保存log的文件名,arg[2]要打印的日志内容

    :return 返回logger 对象"""

    #创建一个logger对象

    logger =logging.getLogger(args[0])

    logger.setLevel(logging.DEBUG)#创建一个向屏幕输入的handler对象

    ch =logging.StreamHandler(sys.stdout)

    ch.setLevel(logging.DEBUG)#创建一个像文件输入的handler对象

    log_file = os.path.join(log_path, "%s--%s_log" % (args[1], self.now_time))

    fh= logging.FileHandler(log_file, mode="a+", encoding="utf-8")

    fh.setLevel(logging.DEBUG)#设置log输入格式

    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    ch.setFormatter(formatter)

    fh.setFormatter(formatter)#logger,添加handler对象

    logger.addHandler(ch)

    logger.addHandler(fh)

    logger.info(args[2])#在记录日志之后移除句柄, 不然会重复打印日志

    logger.removeHandler(fh)

    logger.removeHandler(ch)returnlogger

    @staticmethoddef log_warning(*args):"""根据传入参数错误日志

    :param arg[0]log的功能模块名,arg[1]文件名 arg[2] 需要打印的内容

    :return 返回logger 对象"""

    #创建一个logger对象

    logger =logging.getLogger(args[0])

    logger.setLevel(logging.DEBUG)#创建一个向屏幕输入的handler对象

    ch =logging.StreamHandler(sys.stdout)

    ch.setLevel(logging.DEBUG)#创建一个像文件输入的handler对象

    log_file = os.path.join(log_path, args[1])

    fh= logging.FileHandler(log_file, mode="a+", encoding="utf-8")

    fh.setLevel(logging.DEBUG)#设置log输入格式

    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    ch.setFormatter(formatter)

    fh.setFormatter(formatter)#logger,添加handler对象

    logger.addHandler(ch)

    logger.addHandler(fh)

    logger.warning(args[2])#在记录日志之后移除句柄, 不然会重复打印日志

    logger.removeHandler(fh)

    logger.removeHandler(ch)print("aaa")returnlogger#@staticmethod

    deflog_debug(self,message):"""根据传入参数错误日志

    :param arg[0]log的功能模块名,arg[1]文件名 arg[2] 需要打印的内容

    :return 返回logger 对象"""

    #创建Logger

    logger =logging.getLogger()

    logger.setLevel(logging.DEBUG)#创建Handler

    #终端Handler

    consoleHandler =logging.StreamHandler(sys.stdout)

    consoleHandler.setLevel(logging.DEBUG)#文件Handler

    fileHandler = logging.FileHandler('ing.log', mode='w', encoding='UTF-8')

    fileHandler.setLevel(logging.NOTSET)#Formatter

    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    consoleHandler.setFormatter(formatter)

    fileHandler.setFormatter(formatter)#添加到Logger中

    logger.addHandler(consoleHandler)

    logger.addHandler(fileHandler)returnlogger.debug(message)#if __name__ == "__main__":#A=LOG()#A.log_debug('123')

    示例代码--删减版

    c、报告输入

    报告输出依赖库主要为requests、unittest、下面为代码示例:

    importrequestsfrom data.export_url importExportERLfrom data.request_dict importRequestDatafrom logic.log_print importLOGfrom logic.database importConnectDatabasefrom data.custom_variable importGlobalVariableclassExportLogic(object):"""ExportLogic 接口主逻辑类"""

    def __init__(self):

    self.Request=RequestData()

    self.Url=ExportERL()

    self.ConnectDatabase=ConnectDatabase()

    self.Log=LOG()

    self.Custom_variable=GlobalVariable()

    @staticmethoddef request_post(*args, **kwargs):"""传入请求参数,返回json请求结果

    :param args:

    :param kwargs: json:请求数据, url:请求路径, header:请求头

    :return:"""request_data= kwargs.get("json")

    request_url= kwargs.get("url")

    request_header= kwargs.get("header")

    response_json= requests.post(url=request_url, data=request_data, headers=request_header).json()returnresponse_json

    @staticmethoddef request_post_json(*args, **kwargs):"""传入请求参数,返回json请求结果

    :param args:

    :param kwargs: json:请求数据, url:请求路径, header:请求头

    :return:"""request_data= kwargs.get("json")

    request_url= kwargs.get("url")

    request_header= kwargs.get("header")

    response_json= requests.post(url=request_url, json=request_data, headers=request_header)returnresponse_json

    @staticmethoddef request_post_file(*args, **kwargs):"""上传接口独有

    :param args:

    :param kwargs: json:请求数据, url:请求路径, header:请求头, file:文件路径

    :return:"""request_data= kwargs.get("json")

    request_url= kwargs.get("url")

    request_header= kwargs.get("header")

    request_file= kwargs.get("files")

    response_json= requests.post(url=request_url, data=request_data, files=request_file,

    headers=request_header).json()returnresponse_jsonif __name__ == "__main__":

    b= ExportLogic()

    requests库演示代码--删减版

    importunittestimportosimportHTMLTestReportCNimportdatetimefrom logic.export_logic importExportLogicfrom data.custom_variable importGlobalVariablefrom data.export_url importExportERLfrom logic.public_class importPublicfrom data.request_dict importRequestDatafrom logic.log_print importLOGfrom logic.database importConnectDatabasefrom data.conf_dict importConfDatafrom logic.send_email importSendEmailimportrandom,requestsclassLZExportCase(unittest.TestCase):"""新浪有借有还接口测试用例"""

    #全距

    PHONE =Public().create_phone()#提交五项资料的Header

    HEADER = GlobalVariable().get_header('lz_Header')#修改手机号的Header

    HEADER1 = GlobalVariable().get_header('lz_Header')

    BASEID= ''PERIODNUM= ''IMGID=''Repayid= ''Periodnum_= ''

    defsetUp(self):

    self.Export_logic=ExportLogic()

    self.Export_url=ExportERL()

    self.Public=Public()

    self.Request_data=RequestData()

    self.Custom_variable=GlobalVariable()

    self.Log=LOG()

    self.ConnectDatabase=ConnectDatabase()

    self.Conf_data=ConfData()

    self.password= GlobalVariable().get_variable("password")

    self.phone=Public().create_phone()

    self.newphone= GlobalVariable().get_variable("YJ_newphone")#self.report_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "report")

    self.log_path = os.path.dirname(os.path.dirname(__file__))

    self.path= os.path.join(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "static"),"logo.jpg")deftearDownC(self):pass

    #os.remove(os.path.join(self.report_path, "report.html"))

    #os.remove(os.path.join(os.path.join(self.path, "log"), "Export_log"))

    deftest_085_FileLoad(self):"""Case--上传文件(saveType正常)"""url= self.Export_url.get_export_url("LZ_test_url", "File")

    request_json= self.Request_data.get_request_data('File')

    file_= open(self.path, 'rb')

    file={"file": ('logo.jpg', file_, 'image/jpeg')

    }

    request_json["saveType"] = '1'request_json= self.Public.sign_md5(keys="lz_test_keys", json=request_json)

    self.Log.log_info(self._testMethodDoc.strip(), self.Conf_data.get_conf_data("log_name", "LZ"),"%s request data:%s" %(self._testMethodName, request_json))

    response_json= self.Export_logic.request_post_file(url=url, json=request_json, files=file, header=self.HEADER)

    LZExportCase.IMGID= response_json['data']['id']

    self.Log.log_info(self._testMethodDoc.strip(), self.Conf_data.get_conf_data("log_name", "LZ"),"%s response data:%s" %(self._testMethodName, response_json))

    self.assertEqual(self.Conf_data.get_conf_PromptMsg("prompt_msg", "LZ",'data_correct')['msg'], response_json['msg']) \and self.assertEqual(self.Conf_data.get_conf_PromptMsg("prompt_msg", "LZ",'data_correct')['code'], response_json['code'])

    file_.close()deftest_086_HeadImg(self):"""Case--修改头像(headimgId正常)"""url= self.Export_url.get_export_url("LZ_test_url", "HeadImg")

    request_json= self.Request_data.get_request_data('HeadImg')

    request_json["headimgId"] =LZExportCase.IMGID

    request_json= self.Public.sign_md5(keys="lz_test_keys", json=request_json)

    self.Log.log_info(self._testMethodDoc.strip(), self.Conf_data.get_conf_data("log_name", "LZ"),"%s request data:%s" %(self._testMethodName, request_json))

    response_json= self.Export_logic.request_post(url=url, json=request_json, header=self.HEADER)

    self.Log.log_info(self._testMethodDoc.strip(), self.Conf_data.get_conf_data("log_name", "LZ"),"%s response data:%s" %(self._testMethodName, response_json))

    self.assertEqual(self.Conf_data.get_conf_PromptMsg("prompt_msg", "LZ",'data_correct')['msg'], response_json['msg']) \and self.assertEqual(self.Conf_data.get_conf_PromptMsg("prompt_msg", "LZ",'data_correct')['code'], response_json['code'])deftest_087_HeadImg(self):"""Case--修改头像(headimgId错误)"""url= self.Export_url.get_export_url("LZ_test_url", "HeadImg")

    request_json= self.Request_data.get_request_data('HeadImg')

    request_json["headimgId"] = '3213adcx213vcv'request_json= self.Public.sign_md5(keys="lz_test_keys", json=request_json)

    self.Log.log_info(self._testMethodDoc.strip(), self.Conf_data.get_conf_data("log_name", "LZ"),"%s request data:%s" %(self._testMethodName, request_json))

    response_json= self.Export_logic.request_post(url=url, json=request_json, header=self.HEADER)

    self.Log.log_info(self._testMethodDoc.strip(), self.Conf_data.get_conf_data("log_name", "LZ"),"%s response data:%s" %(self._testMethodName, response_json))

    self.assertEqual(self.Conf_data.get_conf_PromptMsg("prompt_msg", "LZ",'headimgId_ERROR')['msg'], response_json['msg']) \and self.assertEqual(self.Conf_data.get_conf_PromptMsg("prompt_msg", "LZ",'headimgId_ERROR')['code'], response_json['code'])deftest_088_HeadImg(self):"""Case--修改头像(headimgId为空)"""url= self.Export_url.get_export_url("LZ_test_url", "HeadImg")

    request_json= self.Request_data.get_request_data('HeadImg')

    request_json["headimgId"] = ''request_json= self.Public.sign_md5(keys="lz_test_keys", json=request_json)

    self.Log.log_info(self._testMethodDoc.strip(), self.Conf_data.get_conf_data("log_name", "LZ"),"%s request data:%s" %(self._testMethodName, request_json))

    response_json= self.Export_logic.request_post(url=url, json=request_json, header=self.HEADER)

    self.Log.log_info(self._testMethodDoc.strip(), self.Conf_data.get_conf_data("log_name", "LZ"),"%s response data:%s" %(self._testMethodName, response_json))

    self.assertEqual(self.Conf_data.get_conf_PromptMsg("prompt_msg", "LZ",'headimgId_NULL')['msg'], response_json['msg']) \and self.assertEqual(self.Conf_data.get_conf_PromptMsg("prompt_msg", "LZ",'headimgId_NULL')['code'], response_json['code'])if __name__ == '__main__':

    Send_mail=SendEmail()

    now_time= datetime.datetime.now().strftime("%Y%m%d%H%M")

    module_name= os.path.basename(__file__).split(".")[0]

    module= __import__(module_name)

    path= os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "report")

    logo_path= os.path.join(os.path.join(path, "static"),"logo.jpg")

    fp= open(os.path.join(path, "report--%s.html" % now_time), "wb")

    runner= HTMLTestReportCN.HTMLTestRunner(stream=fp)

    all_suite=unittest.defaultTestLoader.loadTestsFromModule(module)

    runner.run(all_suite)

    fp.close()

    SendEmail.send_email(Send_mail)

    unittest库演示代码--删减版

    d、邮件发送

    邮件发送依赖两个python内置库smtplib、email:

    importosimportsmtplibimportemail.mime.multipartimportemail.mime.textfrom email importencodersimportdatetimefrom data.conf_dict importConfDatafrom logic.public_class importPublicclassSendEmail(object):def __init__(self):

    self.conf_data=ConfData()

    self.sender= self.conf_data.get_conf_data("email", "sender")

    self.receiver= self.conf_data.get_conf_data("email", "receiver")

    self.SMTP_server= self.conf_data.get_conf_data("email", "SMTP_server")

    self.username= self.conf_data.get_conf_data("email", "username")

    self.password= self.conf_data.get_conf_data("email", "password")

    self.content= self.conf_data.get_conf_data("email", "content")

    self.now_time= datetime.datetime.now().strftime("%Y%m%d%H%M")

    self.report_path= os.path.join(os.path.dirname(os.path.dirname(__file__)), "report")

    self.log_path= os.path.join(os.path.dirname(os.path.dirname(__file__)), "log")defcreate_msg(self,receiver):"""此函数主要构建收发邮件联系人、邮件正文、邮件附件、邮件标题

    :return:"""

    #构建邮件正文

    msg =email.mime.multipart.MIMEMultipart()

    msg["from"] =self.sender

    msg["to"] =receiver

    msg['subject'] = "API自动化测试报告"txt=email.mime.text.MIMEText(self.content)

    msg.attach(txt)#构建邮件附件之一:自动化测试报告

    report_name = Public.get_new_file(path=self.report_path)

    report_path=os.path.join(self.report_path, report_name)

    report= email.mime.text.MIMEText(open(report_path, "rb")

    .read(),'html', 'utf-8')

    report["Content-Type"] = 'application/octet-stream'report.add_header('Content-Disposition', 'attachment', filename=('gbk', '', report_name))

    encoders.encode_base64(report)

    msg.attach(report)#构建邮件附件之一:测试日志

    log_name = Public.get_new_file(path=self.log_path)

    log_path=os.path.join(self.log_path, log_name)

    info_log= email.mime.text.MIMEText(open(log_path, 'rb').read(), 'base64', 'utf-8')

    info_log["Content-Type"] = 'application/octet-stream'info_log.add_header('Content-Disposition', 'attachment', filename=('gbk', '', log_name))

    encoders.encode_base64(info_log)

    msg.attach(info_log)returnmsgdef send_email(self,*args):"""创建实例,发送邮件

    :return:"""receiver= self.conf_data.get_conf_data("email", "%s_receiver" % args[0][0]) if args elseself.receiver

    msg=self.create_msg(receiver)

    smtp= smtplib.SMTP_SSL(self.SMTP_server, 465) #在Linux端使用ssL方式连接邮箱服务器

    #smtp.connect(self.SMTP_server, 465) # 在windows端使用connect方式连接邮箱服务器

    smtp.login(self.username, self.password)

    smtp.sendmail(self.sender, receiver.split(","), msg.as_string())

    smtp.quit()if __name__ == "__main__":

    s=SendEmail()

    s.send_email()

    示例代码

    展开全文
  • Python接口自动化测试

    2020-10-25 23:58:20
    如何简单使用python进行接口自动化测试 一,简介 从事测试行业不久,但是本人深深爱上了测试这个岗位,从一开始的功能测试,再到接口,性能,再到现在接触了python这门语言,测试领域很长,希望抱着谦逊学习的态度在...

    如何简单使用python进行接口自动化测试

    一,简介

    从事测试行业不久,但是本人深深爱上了测试这个岗位,从一开始的功能测试,再到接口,性能,再到现在接触了python这门语言,测试领域很长,希望抱着谦逊学习的态度在这条路上一直走下去,嗨,扯远了,看正文。。。

    二,环境的搭建

    安装好了python2.7版本以上,我装的是python3.7.8版本
    安装requests : pip install requests
    安装pytest库:pip install pytest 这里我装的是pytest ": “6.1.1
    安装自动生成测试报告的包:pytest-html v2.1.1
    另外最好还要安装一个pycharm,方便编写代码

    三,准备好接口文档(供应测试)

    下面使用requests实现登录接口,从登录接口中获取access_token 用于其他接口的访问

    import requests
    
    
    # 此登录接口用于获取token
    # 该登录接口为post方法,参数为json格式
    def test_login():
        base_url = ~~'https://testbuyerapi.chinagoods.com'~~ 
        fordata = {
            "scope": "buyer",
            "grant_type": "password",
            "password": "123456a",
            "username": "18699268888",
            "area_code": "+86"
        }
        r = requests.post(url=base_url + "/v1/auth/login", json=fordata)
        access_token = r.json()['access_token']
        return access_token
    
    
    if __name__ =='__main__':
        print(test_login())
    

    其实这个登录接口既可以返回 token,可以给其他接口使用,例如:领劵接口 ;大家也可以对这个登录进行断言

    import requests
    import pytest
    
    
    # 此登录接口用于获取token
    # 该登录接口为post方法,参数为json格式
    
    def test_login():
        base_url='https://testbuyerapi.chinagoods.com'
        fordata = {
            "scope": "buyer",
            "grant_type": "password",
            "password": "123456a",
            "username": "18699268888",
            "area_code": "+86"
        }
        r = requests.post(url=base_url + "/v1/auth/login", json=fordata)
        access_token = r.json()['access_token']
        return access_token
        assert r.json()['token_type'] == 'bearer'
    
    
    
    
    
    if __name__ =='__main__':
        print(test_login())
    

    下面就是使用pytest执行登录这个接口

    
    ```bash
    (venv) testfile@mikecrodeMBP pythonProject2 % pytest testcase/test_05.py
    ============================================================================= test session starts =============================================================================
    platform darwin -- Python 3.7.8, pytest-6.1.1, py-1.9.0, pluggy-0.13.1
    rootdir: /Users/testfile/PycharmProjects/pythonProject2
    plugins: metadata-1.10.0, html-2.1.1
    collected 1 item                                                                                                                                                              
    
    testcase/test_05.py .                                                                                                                                                   [100%]
    
    ============================================================================== 1 passed in 0.78s ==============================================================================
    

    1 passed in 0.78s 代表刚才的断言执行通过
    另外,可以利用pytest-html生成测试报告

    pytest testcase/test_05 --html==test_report
    
    

    会自动在目录下面生成一个文件名为的test_report报告,用浏览器打开:如下

    (venv) testfile@mikecrodeMBP pythonProject2 % pytest testcase/test_05.py --html==test_report
    ============================================================================= test session starts =============================================================================
    platform darwin -- Python 3.7.8, pytest-6.1.1, py-1.9.0, pluggy-0.13.1
    rootdir: /Users/testfile/PycharmProjects/pythonProject2
    plugins: metadata-1.10.0, html-2.1.1
    collected 1 item                                                                                                                                                              
    
    testcase/test_05.py .                                                                                                                                                   [100%]
    
    ------------------------------------------- generated html file: file:///Users/testfile/PycharmProjects/pythonProject2/=test_report -------------------------------------------
    ============================================================================== 1 passed in 0.90s ==============================================================================
    

    这样就好了,生成了报告

    在这里插入图片描述

    展开全文
  • python 接口自动化测试

    2019-12-23 15:33:57
    最近对公司项目进行了接口自动化测试,做个总结,方便后期查看 1 测试前背景:项目接口的说明文档可使用;所有接口都经过冒烟测试 2 测试准备文档: 2.1 确定测试范围(excel列出需要测试的接口,以及优先级,...
  • 本节开始,开始介绍python接口自动化测试,首先需要搭建python开发环境,到https://www.python.org/下载python版本直接安装就以了,建议 下载python2.7.11版本,当然,也是可以下载python最新版本的。 接口测试是...
  • 之前小编写过Rest-assuert接口测试框架,它是基于java的,那么怎么轻轻松松玩转python接口自动化测试呢?今天小编就写写如何使用python Request进行接口自动测试。学习任何一门技术一门语言,首先要知道从哪些学起,...
  • 在前面的几篇文章中,postman接口用例转化为python自动化测试用例postman接口用例转化为python自动化测试用例(二)postman接口用例转化为python自动化测试用例(三)python自动化测试用例之----引入ddt数据驱动四篇文章...
  • 本书主要介绍如何用Python实现接口自动化测试。全书主要内容包括接口基础、接口手工测试、编程前的准备、用Python处理MySQL数据库、用Python发送HTTP请求、用Python处理HTTP返回包、用Python导出测试数据、接口自动...
  • 导读:有许多小伙伴关注Python接口自动化测试框架实战 从设计到开发这一问题。关于此IT猫也是收集了很多材料,加上自己的理解,分享给大家。下面就来一起看一看IT猫收集到的关于《Python接口自动化测试框架实战 从...
  • python接口自动化测试框架---包括请求的封装、数据库操作、多断言、ddt数据驱动、多种请求方式等
  • 未来功能测试依然存在,只是自动化测试会分一杯羹,这个是市场大环境,大趋势,这里说一下python自动化测试框架层级结构.python自动化项目结构目录1.common目录common目录主要适用于写基础性代码和方法,比如连接...
  • python接口自动化测试是PDF文档形式,文档中的实现以Python语言为基础,进行HTTP接口自动化框架,模块包括Excel进行参数化,读取配置文件,读取测试用例,执行测试用例,记录...是学习python接口自动化测试的绝佳文档。
  • Python接口自动化测试视频教程下载课程介绍:此套Python接口自动化测试视频教程适合入门接口测试和学习python+requests自动化的学员学习,教程对http协议、fiddler抓包与测试、requests、session、json、unittest、...
  • 特殊字符极其丰富,手工测试往往需要耗费大量成本,接口自动化测试因其实现简单、维护成本低、容易提高覆盖率等特点,越来越受重视。Python由于可移植性好、第三方库丰富、上手简单而成为一种便...
  • 主要介绍了Python接口自动化测试的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 在利用Python进行接口自动化测试的时候,一般会选择Excel来做测试数据的管理,可以利用openpyxl、xrld或者是xlwt开源包对Excel中的数据进行操作。在common包中创建operate_excel.py文件,对Excel中的数据进行操作...
  • 在做自动化测试时,经常会对一整套业务流程进行一组接口上的测试,这时候接口之间经常会有数据依赖,那么具体要怎么实现这个依赖呢。思路如下:抽取之前接口的返回值存储到全局变量字典中。初始化接口请求时,解析...
  • Python接口自动化测试教程.part1 第一步峰 内置播放器
  • python接口自动化测试框架---包括请求的封装、数据库操作、多断言、ddt数据驱动、多种请求方式等注意事项:运行此项目前,先修改config.ini的路径,此路径为项目本地路径;此接口数据为字典格式,用到实际项目中请...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,695
精华内容 2,278
关键字:

python接口自动化测试

python 订阅