zoukankan      html  css  js  c++  java
  • 【python自学】Python接口自动化测试(转)


     

    写在前面:

    接口测试之前一直使用jmeter来测试,单个接口还好,多个接口的时候,需要传入各种各样的值,感觉工作量挺大的。

    最近学习python,其他java也可以实现,鉴于团队中使用python的人员比较多,所以就想着尝试搭建个python接口自动化的框架。

    对于python而言,我就是个小白,正在不断的充电中。。。

    之前使用java+selenium+TestNG+log4j +Jenkins自己搭建的UI自动化框架很好用,前两天一个项目,三四天时间就把基本流程和功能写完,

    帮助自己减少了不少重复工作量。

    今天呢,也想通过学习python自动化框架+requests+uinitest(或其他更好的框架),来让接口测试更有条不紊。

    加油吧,少年!


    转自:https://www.cnblogs.com/zhengyao9236/p/11122446.html

    1)环境准备:

      接口测试的方式有很多,比如可以用工具(jmeter,postman)之类,也可以自己写代码进行接口测试,工具的使用相对来说都比较简单,重点是要搞清楚项目接口的协议是什么,然后有针对性的进行选择,甚至当工具不太适合项目时需要自己进行开发。

      在我们项目的初期,我们采用的是jmeter进行接口测试,当时觉得这个工具上手简单,团队成员学习成本低,并且接口测试的脚本稍微调整一下还可以用来做性能测试。

      不过随着项目规模、团队人数的不断增长,渐渐的这个工具有适应不了当前项目的需求了,为此我们项目也重新开发了相关接口自动化的平台。但是,但是。。。可能是我让大家中毒太深,现在很多同学一提到接口测试关联到jmeter,为此,我深深感到不安。毕竟jmeter只是个工具,换个项目换个协议你是否还能玩转接口测试呢?session和cookie有什么区别?工具又是怎么实现的呢?

      比如session如何保存,接口依赖如何处理,case如何管理及执行顺序,测试数据如何管理等等题,这个过程也有助于我们更加深刻的理解接口测试和http协议。

      本文主要采用python语言,python中http协议接口相关的库有urllib,urllib2以及reqeusts库,这其中reqeusts库用来起来最方便,因此我也主要采用requests库来做http协议的接口测试。首先来看下需要哪些环境信息:

    一、安装python

      mac下自带安装了python,这个不多说了。

    二、安装虚拟环境:

    我们在一台机器上可以安装多个python版本,为了使每个版本的环境相互不受干扰,可以安装虚拟环境,安装方法如下:

    1、安装virtualenv:pip install virtualenv

    2、新建名为venv的虚拟环境:virtualenv venv

    3、进入新环境:source venv/bin/activate

    4、退出:deactivate

    三、安装requests库:

    >>>pip install requests

    ps:用python做http协议的接口测试会用到这个库。

    四、http测试工具:

    一个使用 Python + Flask 编写的 HTTP 请求和响应服务,该服务主要用于测试 HTTP 库。后续测试我们都基于这个网站。

    http://httpbin.org

    五、在本地搭建httpbin:

    考虑到测试时要不断访问 httpbin 网站,请求过多担心被拉到黑名单,我们自己在本志搭建一套httpbin服务。

    1、安装:pip install gunicorn

    2、安装:pip install httpbin

    3、启动:gunicorn httpbin:app

    至此,环境搭建已经完毕,可以开始玩了~

    (2)requests.get()

    环境搭建好后,接下来我们先来了解一下requests的一些简单使用,主要包括:

    1. requests常用请求方法使用,包括:get,post
    2. requests库中的Session、Cookie的使用
    3. 其它高级部分:认证、代理、证书验证、超时配置、错误异常处理等。

    本节首先来了解一下requests库中如何发送get请求:

    一、看下方法定义:

    1、到官方文档去了下requests.get()方法的定义,如下:

    2、点击右上角的【source】,看一下它的源码如下:

    看到最后一行return,get方法最后是通过调用 requests.request 方法实现的,其实在其它的请求方法如post,put,head,delete等方法都是调用的request方法,然后把请求方法的类型传递给request方法第一个参数。

    3、HTTP协议是一个基于请求/响应模式的、无状态的,应用层协议。既然有请求,就有响应,来看下resquest中常用的响应信息:

    二、get方法简单使用: 

    1、不带参数的get:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    #不带参数的get
    
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "get"
    
    url = ''.join([host,endpoint])
    r = requests.get(url)
    #response = r.json()
    
    print type(r.text)
    print (eval(r.text))
    复制代码
    复制代码

    输出:

    复制代码
    复制代码
    {
        'origin': '183.14.133.88',
        'headers': {
            'Connection': 'close',
            'Host': 'httpbin.org',
            'Accept-Encoding': 'gzip,
            deflate',
            'Accept': '*/*',
            'User-Agent': 'python-requests/2.18.1'
        },
        'args': {
            
        },
        'url': 'http: //httpbin.org/get'
    }
    复制代码
    复制代码

    2、 带参数的get:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    #带参数的get
    
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "get"
    
    url = ''.join([host,endpoint])
    params = {"show_env":"1"}
    r = requests.get(url=url,params=params)
    
    print r.url
    复制代码
    复制代码

     输出:

    复制代码
    复制代码
    http://httpbin.org/get?show_env=1
    {
        'origin': '183.14.133.88',
        'headers': {
            'X-Request-Id': 'ebe922b4-c463-4fe9-9faf-49748d682fd7',
            'Accept-Encoding': 'gzip,
            deflate',
            'X-Forwarded-Port': '80',
            'Total-Route-Time': '0',
            'Connection': 'close',
            'Connect-Time': '0',
            'Via': '1.1vegur',
            'X-Forwarded-For': '183.14.133.88',
            'Accept': '*/*',
            'User-Agent': 'python-requests/2.18.1',
            'X-Request-Start': '1504755961007',
            'Host': 'httpbin.org',
            'X-Forwarded-Proto': 'http'
        },
        'args': {
            'show_env': '1'
        },
        'url': 'http: //httpbin.org/get?show_env=1'
    }
    复制代码
    复制代码

    3、带header的get:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "get"
    
    url = ''.join([host,endpoint])
    headers = {"User-Agent":"test request headers"}
    
    r = requests.get(url)
    r = requests.get(url,headers=headers)
    #response = r.json()
    print (eval(r.text))['headers']['User-Agent']
    复制代码
    复制代码

    输出:

    test request headers

    4、同时带参数和header:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "get"
    
    url = ''.join([host,endpoint])
    headers = {"User-Agent":"test request headers"}
    params = {"show_env":"1"}
    
    r = requests.get(url)
    r = requests.get(url,headers=headers,params=params)
    
    #response = r.json()
    print (eval(r.text))['headers']['User-Agent']
    print r.url
    复制代码
    复制代码

    输出:

    test request headers
    http://httpbin.org/get?show_env=1

    (3)requests.post()

    一、方法定义

    二、post方法简单使用

      1、带数据的post

      2、带header的post

      3、带json的post

      4、带参数的post

      5、普通文件上传

      6、定制化文件上传

      7、多文件上传

    一、方法定义:

    1、到官方文档去了下requests.post()方法的定义,如下:

    2、源码:

    3、常用返回信息:

    二、post方法简单使用:

     1、带数据的post:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "post"
    url = ''.join([host,endpoint])
    data = {'key1':'value1','key2':'value2'}
    
    r = requests.post(url,data=data)
    #response = r.json()
    print (r.text)
    复制代码
    复制代码

    输出:

    复制代码
    复制代码
    {
      "args": {}, 
      "data": "", 
      "files": {}, 
      "form": {
        "key1": "value1", 
        "key2": "value2"
      }, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Connection": "close", 
        "Content-Length": "23", 
        "Content-Type": "application/x-www-form-urlencoded", 
        "Host": "httpbin.org", 
        "User-Agent": "python-requests/2.18.1"
      }, 
      "json": null, 
      "origin": "183.14.133.88", 
      "url": "http://httpbin.org/post"
    }
    复制代码
    复制代码

    2、带header的post:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "post"
    
    url = ''.join([host,endpoint])
    headers = {"User-Agent":"test request headers"}
    
    # r = requests.post(url)
    r = requests.post(url,headers=headers)
    #response = r.json()
    复制代码
    复制代码

    输出:

    复制代码
    复制代码
    {
      "args": {}, 
      "data": "", 
      "files": {}, 
      "form": {}, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Connection": "close", 
        "Content-Length": "0", 
        "Host": "httpbin.org", 
        "User-Agent": "test request headers"
      }, 
      "json": null, 
      "origin": "183.14.133.88", 
      "url": "http://httpbin.org/post"
    }
    复制代码
    复制代码

    3、带json的post:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "post"
    
    url = ''.join([host,endpoint])
    data = {
        "sites": [
                    { "name":"test" , "url":"www.test.com" },
                    { "name":"google" , "url":"www.google.com" },
                    { "name":"weibo" , "url":"www.weibo.com" }
        ]
    }
    
    r = requests.post(url,json=data)
    # r = requests.post(url,data=json.dumps(data))
    response = r.json()
    复制代码
    复制代码

    输出:

    复制代码
    复制代码
    {
      "args": {}, 
      "data": "{"sites": [{"url": "www.test.com", "name": "test"}, {"url": "www.google.com", "name": "google"}, {"url": "www.weibo.com", "name": "weibo"}]}", 
      "files": {}, 
      "form": {}, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Connection": "close", 
        "Content-Length": "140", 
        "Content-Type": "application/json", 
        "Host": "httpbin.org", 
        "User-Agent": "python-requests/2.18.1"
      }, 
      "json": {
        "sites": [
          {
            "name": "test", 
            "url": "www.test.com"
          }, 
          {
            "name": "google", 
            "url": "www.google.com"
          }, 
          {
            "name": "weibo", 
            "url": "www.weibo.com"
          }
        ]
      }, 
      "origin": "183.14.133.88", 
      "url": "http://httpbin.org/post"
    }
    复制代码
    复制代码

    4、带参数的post:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "post"
    
    url = ''.join([host,endpoint])
    params = {'key1':'params1','key2':'params2'}
    
    # r = requests.post(url)
    r = requests.post(url,params=params)
    #response = r.json()
    print (r.text)
    复制代码
    复制代码

    输出:

    {
    "args": {
    "key1": "params1", 
    "key2": "params2"
    }, 
    "data": "", 
    "files": {}, 
    "form": {}, 
    "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Connection": "close", 
    "Content-Length": "0", 
    "Host": "httpbin.org", 
    "User-Agent": "python-requests/2.18.1"
    }, 
    "json": null, 
    "origin": "183.14.133.88", 
    "url": "http://httpbin.org/post?key2=params2&key1=params1"
    }

    5.普通文件上传:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "post"
    
    url = ''.join([host,endpoint])
    #普通上传
    files = {
                'file':open('test.txt','rb')
            }
    
    r = requests.post(url,files=files)
    print (r.text)
    复制代码
    复制代码

    输出:

    复制代码
    复制代码
    {
      "args": {}, 
      "data": "", 
      "files": {
        "file": "hello world!
    "
      }, 
      "form": {}, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Connection": "close", 
        "Content-Length": "157", 
        "Content-Type": "multipart/form-data; boundary=392865f79bf6431f8a53c9d56c62571e", 
        "Host": "httpbin.org", 
        "User-Agent": "python-requests/2.18.1"
      }, 
      "json": null, 
      "origin": "183.14.133.88", 
      "url": "http://httpbin.org/post"
    }
    复制代码
    复制代码

    6.定制化文件上传:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "post"
    
    url = ''.join([host,endpoint])
    #自定义文件名,文件类型、请求头
    files = {
            'file':('test.png',open('test.png','rb'),'image/png')
    }
    
    r = requests.post(url,files=files)
    print (r.text)heman793
    复制代码
    复制代码

    7.多文件上传:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "post"
    
    url = ''.join([host,endpoint])
    #多文件上传
    files = [
        ('file1',('test.txt',open('test.txt', 'rb'))),
        ('file2', ('test.png', open('test.png', 'rb')))
        ]
    
    r = requests.post(url,files=files)
    print (r.text)
    复制代码
    复制代码

    8.流式上传:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "post"
    
    url = ''.join([host,endpoint])
    
    #流式上传
    with open( 'test.txt' ) as f:
        r = requests.post(url,data = f)
    
    print (r.text)
    复制代码
    复制代码

    输出:

    复制代码
    复制代码
    {
      "args": {}, 
      "data": "hello world!
    ", 
      "files": {}, 
      "form": {}, 
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Connection": "close", 
        "Content-Length": "13", 
        "Host": "httpbin.org", 
        "User-Agent": "python-requests/2.18.1"
      }, 
      "json": null, 
      "origin": "183.14.133.88", 
      "url": "http://httpbin.org/post"
    }
    复制代码
    复制代码

    (4)Cookie&Session

    掌握了前面几节的的内容,就可以做一些简单的http协议接口的请求发送了,但是这些还不够。HTTP协议是一个无状态的应用层协议,也就是说前后两次请求是没有任何关系的,那如果我们测试的接口之前有相互依赖关系怎么办呢(比如我要在博客园发文章,是需要先登录的),这时我们就要用到cookie和session技术来保持客户端与服务器端连接的状态,这也就是本节要介绍的内容:

    一、Cookie:

    1、获取cookie:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    #获取cookie
    import requests
    import json
    
    url = "https://www.baidu.com/"
    r = requests.get(url)
    
    #将RequestsCookieJar转换成字典
    c = requests.utils.dict_from_cookiejar(r.cookies)
    
    print r.cookies
    print c
    
    for a in r.cookies:
        print a.name,a.value
    复制代码
    复制代码

    输出:

    <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]>
    {'BDORZ': '27315'}
    BDORZ 27315

    2、发送Cookie

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    #发送cookie到服务器
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "cookies"
    
    url = ''.join([host,endpoint])
    #方法一:简单发送
    # cookies = {"aaa":"bbb"}
    # r = requests.get(url,cookies=cookies)
    # print r.text
    
    #方法二:复杂发送
    s = requests.session()
    c = requests.cookies.RequestsCookieJar()
    c.set('c-name','c-value',path='/xxx/uuu',domain='.test.com')
    s.cookies.update(c) 
    复制代码
    复制代码

    二、Session

    1、保持会话同步:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "cookies"
    
    url = ''.join([host,endpoint])
    url1 = "http://httpbin.org/cookies/set/sessioncookie/123456789"
    
    r = requests.get(url)
    print r.text
    
    print "------"
    
    
    s = requests.session()    #初始化一个session对象
    s.get(url1)               #cookie的信息存在了session中
    r = s.get(url)
    
    print r.text
    复制代码
    复制代码

    输出:

    复制代码
    复制代码
    {
      "cookies": {}
    }
    
    ------
    {
      "cookies": {
        "sessioncookie": "123456789"
      }
    }
    复制代码
    复制代码

    2、保存绘画信息:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "headers"
    
    url = ''.join([host,endpoint])
    
    header1 = {"testA":"AAA"}
    header2 = {"testB":"BBB"}
    
    s = requests.session()    #初始化一个session对象
    s.headers.update(header1)   #已经存在于服务中的信息
    r = s.get(url,headers=header2) #发送新的信息
    
    print r.text
    复制代码
    复制代码

    输出:

    复制代码
    复制代码
    {
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Connection": "close", 
        "Host": "httpbin.org", 
        "Testa": "AAA", 
        "Testb": "BBB", 
        "User-Agent": "python-requests/2.18.1"
      }
    }
    复制代码
    复制代码

    3.删除已存在的会话信息,保存为None

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    import json
    
    host = "http://httpbin.org/"
    endpoint = "headers"
    
    url = ''.join([host,endpoint])
    
    header1 = {"testA":"AAA"}
    header2 = {"testB":"BBB"}
    
    s = requests.session()    #初始化一个session对象
    s.headers.update(header1)   #已经存在于服务中的信息
    r = s.get(url,headers=header2) #发送新的信息
    
    print r.text
    
    print '--------'
    
    s.headers['testA'] = None   #删除会话里的信息testA
    r1 = s.get(url,headers = header2)
    print r1.text
    复制代码
    复制代码
    复制代码
    复制代码
    {
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Connection": "close", 
        "Host": "httpbin.org", 
        "Testa": "AAA", 
        "Testb": "BBB", 
        "User-Agent": "python-requests/2.18.1"
      }
    }
    
    --------
    {
      "headers": {
        "Accept": "*/*", 
        "Accept-Encoding": "gzip, deflate", 
        "Connection": "close", 
        "Host": "httpbin.org", 
        "Testb": "BBB", 
        "User-Agent": "python-requests/2.18.1"
      }
    }
    复制代码
    复制代码

    4、提供默认数据:

    复制代码
    复制代码
    s = requests.Session()
    s.auth = ('user', 'pass')
    s.headers.update({'x-test': 'true'})
    
    # both 'x-test' and 'x-test2' are sent
    s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
    复制代码
    复制代码

    参考:

    http://docs.python-requests.org/en/master/user/quickstart/#cookies
    http://docs.python-requests.org/en/master/user/advanced/#session-objects

    (5)其他(认证&代理&超时设置)

    一、认证

    1、基本认证:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    import requests
    
    url = "http://httpbin.org/basic-auth/user/passwd"
    
    r1 = requests.get(url)
    print "未提供用户名密码:" + str(r1.status_code)
    
    #Basic Authentication
    r2 = requests.get(url,auth=('user','passwd'))
    print "已提供用户名密码:" + str(r2.status_code)
    复制代码
    复制代码

    输出:

    未提供用户名密码:401
    已提供用户名密码:200

    2、数字认证:

    >>> from requests.auth import HTTPDigestAuth
    >>> url = 'http://httpbin.org/digest-auth/auth/user/pass'
    >>> requests.get(url, auth=HTTPDigestAuth('user', 'pass'))
    <Response [200]>

    3、OAuth认证:

      参考:http://docs.python-requests.org/en/master/user/authentication/

    二、代理

    1、方法一:proxy参数:

    复制代码
    复制代码
    import requests
    
    proxies = {
      "https": "http://41.118.132.69:4433"
    }
    r = requests.post("http://httpbin.org/post", proxies=proxies)
    print r.text
    复制代码
    复制代码

    2、方法二:设置环境变量:

    复制代码
    复制代码
    $ export HTTP_PROXY="http://10.10.1.10:3128"
    $ export HTTPS_PROXY="http://10.10.1.10:1080"
    
    $ python
    >>> import requests
    >>> requests.get('http://example.org')
    复制代码
    复制代码

    3、HTTP Basic Auth使用代理方法:http://user:password@host/

    proxies = {'http': 'http://user:pass@10.10.1.10:3128/'}

    三、证书验证

    1、SSL证书(HTTPS):

    import requests
    
    #跳过12306 的证书验证,把 verify 设置为 False: 
    r = requests.get('https://kyfw.12306.cn/otn/', verify=False)
    print r.text

    2、客户端证书:

    >>> requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))
    <Response [200]>

    or

    s = requests.Session()
    s.cert = '/path/client.cert'

    四、超时配置

    1 、利用timeout参数来配置最大请求时间:

    r = requests.get('https://github.com', timeout=5)

    2、设置timeout=None,告诉请求永远等待响应,而不将请求作为超时值传递

    r = requests.get('https://github.com', timeout=None)

    五、错误异常:

    1、所有Requests显式抛出的异常都继承自:requests.exctptions.RequestException

    2、遇到网络问题(如:DNS查询失败,拒绝连接等)时,requests会抛出一个 ConnectionError 异常

    3、遇到罕见的无效HTTP响应时,Request则会抛出一个 HTTPError 异常

    4、若请求超时,则抛出一个 Timeout 异常

    5、若请求超过了最大的重写向次数,则会抛出一个 TooManyRedirects 异常

     

    (6)unittest-单个用例管理:

    上面主要介绍了环境搭建和requests库的使用,可以使用这些进行接口请求的发送。但是如何管理接口案例?返回结果如何自动校验?这些内容光靠上面五节是不行的,因此从本节开始我们引入python单元测试框架 unittest,用它来处理批量用例管理,校验返回结果,初始化工作以及测试完成后的环境复原工作等等。

    一、单个用例管理起来比较简单,参考如下图,单个用例一般多用在调试的时候:

    二、代码如下:

    复制代码
    复制代码
    # -*- coding:utf-8 -*-
    # 单个用例执行
    # 1、导入模块
    import unittest
    
    # 2、继承自unittest.TestCase类
    class TestOne(unittest.TestCase):
        # 3、配置环境:进行测试前的初始化工作
        def setUp(self):
  • 相关阅读:
    HDU 5583 Kingdom of Black and White 水题
    HDU 5578 Friendship of Frog 水题
    Codeforces Round #190 (Div. 2) E. Ciel the Commander 点分治
    hdu 5594 ZYB's Prime 最大流
    hdu 5593 ZYB's Tree 树形dp
    hdu 5592 ZYB's Game 树状数组
    hdu 5591 ZYB's Game 博弈论
    HDU 5590 ZYB's Biology 水题
    cdoj 1256 昊昊爱运动 预处理/前缀和
    cdoj 1255 斓少摘苹果 贪心
  • 原文地址:https://www.cnblogs.com/conquerorren/p/13041555.html
Copyright © 2011-2022 走看看