前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Pytest测试实战(十)

Pytest测试实战(十)

作者头像
无涯WuYa
发布2019-12-19 11:24:02
7150
发布2019-12-19 11:24:02
举报
文章被收录于专栏:Python自动化测试

Pytest测试实战(九)里面,把接口请求的的请求地址,请求参数这些都存储到了yaml文件中,然后使用Pytest的参数化可以很轻松的实现几行代码就能够覆盖多个测试场景,关于测试场景的维护只需要在yaml文件中维护就可以了。下来需要思考的是在前面的文章体系中所有的请求都是GET的请求方法,但是请求方法除了GET还有POST等请求方法,所以在本文章中,加入对请求方法的处理机制,维护的yaml文件的内容为:

代码语言:javascript
复制
---
#查看所有书籍信息
"url": "http://localhost:5000/v1/api/books"
"method": "get"
"expect": '"name": "Python接口自动化测试实战"'
---
#创建书籍信息
"url": "http://localhost:5000/v1/api/books"
"method": "post"
dict1:
  "author": "无涯"
  "done": true
  "name": "Python测试实战"
"expect": '"msg": "添加书籍成功", "status": 1002'
---
#查看id为1的书籍信息
"url": "http://localhost:5000/v1/api/book/1"
"method": "get"
"expect": '"author": "wuya"'
---
#修改id为1的书籍信息
"url": "http://localhost:5000/v1/api/book/1"
"method": "put"
dict1:
  "author": "无涯"
  "done": true
  "name": "Python测试实战"
"expect": '"msg": "更新书的信息成功", "status": 1008'
---
#删除id为1的书籍信息
"url": "http://localhost:5000/v1/api/book/1"
"method": "delete"
"expect": '"msg": "删除书籍成功", "status": 1009'

在如上的yaml文件中可以看到我们刻意的增加了method的字段,通过它我们就很轻松的知道场景对应的请求方法是什么。

下来需要思考的是对请求方法如何封装,在requests的库中,我们可以对request的方法进行二次封装和改造,首先来看源码部分,具体如下:

代码语言:javascript
复制
def request(method, url, **kwargs):
    """Constructs and sends a :class:`Request <Request>`.
    :param method: method for the new :class:`Request` object.
    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary, list of tuples or bytes to send
        in the body of the :class:`Request`.
    :param data: (optional) Dictionary, list of tuples, bytes, or file-like
        object to send in the body of the :class:`Request`.
    :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
    :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
    :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
    :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.
        ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')``
        or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string
        defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers
        to add for the file.
    :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
    :param timeout: (optional) How many seconds to wait for the server to send data
        before giving up, as a float, or a :ref:`(connect timeout, read
        timeout) <timeouts>` tuple.
    :type timeout: float or tuple
    :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``.
    :type allow_redirects: bool
    :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
    :param verify: (optional) Either a boolean, in which case it controls whether we verify
            the server's TLS certificate, or a string, in which case it must be a path
            to a CA bundle to use. Defaults to ``True``.
    :param stream: (optional) if ``False``, the response content will be immediately downloaded.
    :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    Usage::
      >>> import requests
      >>> req = requests.request('GET', 'https://httpbin.org/get')
      <Response [200]>
    """
    # By using the 'with' statement we are sure the session is closed, thus we
    # avoid leaving sockets open which can trigger a ResourceWarning in some
    # cases, and look like a memory leak in others.
    with sessions.Session() as session:
        return session.request(method=method, url=url, **kwargs)

如上的代码是来源于requests库的源码,这部分代码非常的核心,它显示了在requests的请求中关于地址,方法,以及请求头等很多的信息,如json,data,params,verify,cookies的信息。其实在源码中不需要刻意的去关心GET和POST请求方法,因为它都是来自request的方法之上,GET方法的源码如下:

代码语言:javascript
复制
def get(url, params=None, **kwargs):
    r"""Sends a GET request.
    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary, list of tuples or bytes to send
        in the body of the :class:`Request`.
    :param \*\*kwargs: Optional arguments that ``request`` takes.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response
    """
    kwargs.setdefault('allow_redirects', True)
    return request('get', url, params=params, **kwargs)

可以看到,在GET的方法中调用了request的方法,只不对针对GET请求又做了特殊的处理,那么**kwargs是什么,它可能是headers,也可能是cookie,verify的信息等信息。依据如上的信息,封装后的请求方法代码如下:

代码语言:javascript
复制
#!/usr/bin/python3
#coding:utf-8#author:无涯


import  requests


class Request:
   def request(self,url,method='get',**kwargs):
      if method=='get':
         return requests.request(url=url,method=method,**kwargs)
      elif method=='post':
         return requests.request(url=url,method=method,**kwargs)
      elif method=='put':
         return requests.request(url=url,method=method,**kwargs)
      elif method=='delete':
         return requests.request(url=url,method=method,**kwargs)

   def get(self,url,**kwargs):
      return self.request(url=url,method='get',**kwargs)

   def post(self,url,**kwargs):
      return self.request(url=url,method='post',**kwargs)

   def put(self,url,**kwargs):
      return self.request(url=url,method='put',**kwargs)

   def delete(self,url,**kwargs):
      return self.request(url=url,method='delete',**kwargs)

在前面两个步骤的基础上,下来在测试的代码中增加对请求方法的判断,如果是GET请求就去调用GET的请求方法,其他的也是如此,完整的代码如下:

代码语言:javascript
复制
#!/usr/bin/python3
#coding:utf-8
import  pytest
import  yaml
import  os
import  requests
import  json


class Request:
   def request(self,url,method='get',**kwargs):
      if method=='get':
         return requests.request(url=url,method=method,**kwargs)
      elif method=='post':
         return requests.request(url=url,method=method,**kwargs)
      elif method=='put':
         return requests.request(url=url,method=method,**kwargs)
      elif method=='delete':
         return requests.request(url=url,method=method,**kwargs)

   def get(self,url,**kwargs):
      return self.request(url=url,method='get',**kwargs)

   def post(self,url,**kwargs):
      return self.request(url=url,method='post',**kwargs)

   def put(self,url,**kwargs):
      return self.request(url=url,method='put',**kwargs)

   def delete(self,url,**kwargs):
      return self.request(url=url,method='delete',**kwargs)


def readYaml():
   with  open('config.yaml','r')  as f:
      return list(yaml.safe_load_all(f))

@pytest.mark.parametrize('datas',readYaml())
def test_books(datas):
   if datas['method']=='get':
      r=Request().get(url=datas['url'])
      assert  datas['expect'] in json.dumps(r.json(),ensure_ascii=False)
   elif datas['method']=='post':
      r=Request().post(url=datas['url'],json=datas['dict1'])
      assert datas['expect'] in json.dumps(r.json(),ensure_ascii=False)
   elif datas['method']=='put':
      r=Request().put(url=datas['url'],json=datas['dict1'])
      assert datas['expect'] in json.dumps(r.json(), ensure_ascii=False)
   elif datas['method']=='delete':
      r=Request().delete(url=datas['url'])
      assert datas['expect'] in json.dumps(r.json(), ensure_ascii=False)


if __name__ == '__main__':
    pytest.main(["-v","-s","wxPytest.py"])

执行如上的代码,输出的结果信息如下:

谢谢您的阅读和关注,后续会持续更新。您也可以购买本人出版的书籍和视频实战课程,谢谢!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python自动化测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档