Analysis of Python Interface Automation Principle of requests Request Encapsulation
- 2021-11-24 01:58:07
- OfStack
In the last Python interface automation test series articles: Python interface automation analysis Token application principle, introduced token basic concept, operation principle and how to carry token interface to access in automation.
The following mainly describes how to encapsulate requests
Remember the get request and post request we wrote before?
Everyone should realize that each request type is written as a separate function, and the code reusability is not strong.
Next, all request types are encapsulated, and all automation use cases can request with this encapsulated request class
Encapsulate the commonly used get and post requests
import requests
class RequestHandler:
def get(self, url, **kwargs):
""" Encapsulation get Method """
# Get request parameters
params = kwargs.get("params")
headers = kwargs.get("headers")
try:
result = requests.get(url, params=params, headers=headers)
return result
except Exception as e:
print("get Request error : %s" % e)
def post(self, url, **kwargs):
""" Encapsulation post Method """
# Get request parameters
params = kwargs.get("params")
data = kwargs.get("data")
json = kwargs.get("json")
try:
result = requests.post(url, params=params, data=data, json=json)
return result
except Exception as e:
print("post Request error : %s" % e)
def run_main(self, method, **kwargs):
"""
Determine the request type
:param method: Request interface type
:param kwargs: Optional parameters
:return: Interface returns content
"""
if method == 'get':
result = self.get(**kwargs)
return result
elif method == 'post':
result = self.post(**kwargs)
return result
else:
print(' Wrong request interface type ')
if __name__ == '__main__':
# Here's the test code
# get Request interface
url = 'https://api.apiopen.top/getJoke?page=1&count=2&type=video'
res = RequestHandler().get(url)
# post Request interface
url2 = 'http://127.0.0.1:8000/user/login/'
payload = {
"username": "vivi",
"password": "123456"
}
res2 = RequestHandler().post(url2,json=payload)
print(res.json())
print(res2.json())
The result of the request is as follows:
'message': ' Success !',
'result': [{'sid': '31004305',
'text': ' Sheep: Master, get a haircut and trim it a little 1 Just get down ',
'type': 'video',
'thumbnail': 'http://wimg.spriteapp.cn/picture/2020/0410/5e8fbf227c7f3_wpd.jpg',
'video': 'http://uvideo.spriteapp.cn/video/2020/0410/5e8fbf227c7f3_wpd.mp4',
'images': None,
'up': '95',
'down': '1',
'forward': '0',
'comment': '25',
'uid': '23189193',
'name': ' Qingchuan canoe ',
'header': 'http://wimg.spriteapp.cn/profile/large/2019/12/24/5e01934bb01b5_mini.jpg',
'top_comments_content':None,
'top_comments_voiceuri': None,
'top_comments_uid': None,
'top_comments_name': None,
'top_comments_header': None,
'passtime': '2020-04-12 01:43:02'},
{'sid': '30559863',
'text': ' Robot girlfriend, except that she can't have children, she can do anything else, and the price 239000 Yuan ',
'type': 'video',
'thumbnail': 'http://wimg.spriteapp.cn/picture/2020/0306/5e61a41172a1b_wpd.jpg',
'video': 'http://uvideo.spriteapp.cn/video/2020/0306/5e61a41172a1b_wpd.mp4',
'images': None, 'up': '80', 'down': '6',
'forward': '3',
'comment': '20',
'uid': '23131273',
'name': ' Follow the course ',
'header': 'http://wimg.spriteapp.cn/profile/large/2019/07/04/5d1d90349cd1a_mini.jpg',
'top_comments_content': ' A show for the game ',
'top_comments_voiceuri': '',
'top_comments_uid': '10250040',
'top_comments_name': ' No sister user ',
'top_comments_header': 'http://wimg.spriteapp.cn/profile',
'passtime': '2020-04-11 20:43:49'}]}
{'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InZpdmkiLCJleHAiOjE1ODY4NTc0MzcsImVtYWlsIjoidml2aUBxcS5jb20ifQ.k6y0dAfNU2o9Hd9LFfxEk1HKgczlQfUaKE-imPfTsm4',
'user_id': 1,
'username': 'vivi'}
Is this perfect? no, no, no.
The pain points of the above code are as follows:
Large amount of code: only encapsulated get, post requests, plus other request types, large amount of code;
Lack of session management: How to maintain session state between requests.
Let's review the source code of get, post and other requests to see if there are any characteristics.
get request source code:
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 query string for 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)
post request source code:
def post(url, data=None, json=None, **kwargs):
r"""Sends a POST request.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary, list of tuples, bytes, or file-like
object to send in the body of the :class:`Request`.
:param json: (optional) json data to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
"""
return request('post', url, data=data, json=json, **kwargs)
After careful study, it is found that get and post requests return request functions.
Let's study the source code of request again:
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 query string for 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)
The source code looks very long, but it only has 3 lines, most of which are code comments.
As you can see from the source code, whether it is get or post or other request types, the request function is ultimately called.
In this case, instead of defining get method and post method in the class as before, we can define a general method
Call the request function directly
It looks a little round, so it is clear to implement it in code.
import requests
class RequestHandler:
def __init__(self):
"""session Manager """
self.session = requests.session()
def visit(self, method, url, params=None, data=None, json=None, headers=None, **kwargs):
return self.session.request(method,url, params=params, data=data, json=json, headers=headers,**kwargs)
def close_session(self):
""" Shut down session"""
self.session.close()
if __name__ == '__main__':
# Here's the test code
# post Request interface
url = 'http://127.0.0.1:8000/user/login/'
payload = {
"username": "vivi",
"password": "123456"
}
req = RequestHandler()
login_res = req.visit("post", url, json=payload)
print(login_res.text)
Response result:
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InZpdmkiLCJleHAiOjE1ODY4Njk3ODQsImVtYWlsIjoidml2aUBxcS5jb20ifQ.OD4HIv8G0HZ_RCk-GTVAZ9ADRjwqr3o0E32CC_2JMLg",
"user_id": 1,
"username": "vivi"
}
This request package is simple and practical, and of course, small partners can package themselves according to their own needs.
The above is Python interface automation analysis requests request encapsulation principle details, more about Python interface automation requests request encapsulation information please pay attention to other related articles on this site!