Day01--搭建接口自动化框架

Day01–搭建接口自动化框架

作者:Ryhn

简介

从0开始记录搭建一个日常通用的基于pytest的测试框架

安装方式

pip install pytest
pip install requests

初步使用Pytest

能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)

用例命名规则

1、用例文件:所有文件名为 test_ 开头 或者 _test 开头的文件会被识别为用例文件
2:用例类:测试文件中每个Test开头的类就是一个测试用例类
3、测试用例:测试类中每个test开头的方法就是一条测试用例,测试文件中每个test开头的函数也是一条测试用例

def test_demo():
     print(1111)

class Test_de():
     def test_demo2(self):
          print(2222)

     def test_demo3(self):
          print(2222)

在没改动配置文件的情况下,命名规则如图上所示。
但是相关的命名规则,其实我们是可以在配置文件中去改动的

执行情况

pytest的用例进行断言后,若断言失败或者代码报错的情况出现,pytest都会认为该条用例失败
示例:

# -*- coding: utf-8 -*-
# @Author : Ryhn



class Test_de():
     def test_demo2(self):
          assert 1 ==2

     def test_demo3(self):
          print(2222)

常用命令

-v:将命令行里面显示的原本是.代表成功的意思,转化成英文单词类型的成功意思
-s:输出每条用例里面打印到控制台或者日志文件要输出的内容都会显示出来

Conftest.py

pytest的源码其实就是一个用多个插件组成的一个测试框架,就像一台汽车一样,所有的插件组成了这台车子的车架
在车架上再个性化一些自身的需求,就需要通过Confete.py去开发自己的插件。
存放位置:
1.在项目顶格文件夹下则是先执行
2.在测试用例文件夹下的是只作用于该文件夹内的用例

@pytest.fixture() 这个方法常用于conftest文件中,该装饰器是告知pytest它所包装的函数,相当于它内部的一个插件是需要去执行的。
常用在登录相关的时候或者是基础数据配置等其他情况
重点参数:
scope:定义该方法的执行次数(session会话中只执行一次,function所有用例执行前都会执行一次)

# -*- coding: utf-8 -*-
# @Author : Ryhn
import pytest


@pytest.fixture(scope="session", autouse=True)
def demo():
     print(2222222222)
     print("------")

配置文件

官方文档相关介绍地址

ini类型

命名标准:pytest.ini
pytest.ini文件优先于其他文件,即使文件为空也是如此

# pytest.ini
[pytest]
minversion = 6.0
addopts = -vs
testpaths =test

注意! pytest内部默认读取ini的格式是gbk,所以在我们默认创建的ini文件需要注意
对应的文件形式。 如果出现报错,解决方案一种是改源码内的读取文件格式;另一种是改ini的编码格式

toml类型

命名标准: pyproject.toml

[tool.pytest.ini_options]
minversion = "6.0"
addopts = "-ra -q"
testpaths = [
    "tests",
    "integration",
]
cfg类型

命名标准: setup.cfg

[tool:pytest]
minversion = 6.0
addopts = -ra -q
testpaths =
    tests
    integration

入门requests库

简介

Requests 是⽤Python语⾔编写,基于urllib,采⽤Apache2 Licensed开源协议的 HTTP 库。它⽐ urllib 更加⽅便,可以节约我们⼤量的⼯作,完全满⾜HTTP测试需求。

内部封装的方法

只介绍常用的方法
1.Get: 参数包含(url,parmar)

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
    """

    return request("get", url, params=params, **kwargs)

2.Post:参数包含(url,data,json)

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) A JSON serializable Python object 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)

通过阅读源码发现:

其实对外提供的方法,都是再走requests.request()这个方法。所以我们只需要通过调用该方法,即可实现不同请求方式的调用。

再阅读request方法源码发现:

其内部是通过建立一个session会话来发起请求,那么多个接口调用则会建立多个会话。出于节省时间提高效率的基础上,我们其实可以通过共用一个会话来发起多个请求。

最终对requests库封装的代码如下:

# -*- coding: utf-8 -*-
# @Author : Ryhn
import re
import requests
from requests import Request


class RestfulApi(object):
     def __init__(self, base_url):
          if not (re.search(r'http', base_url)):
               base_url = "https://"+ base_url
          self.base_url = base_url
          self.session = requests.Session()

     def send(self, method: str):
          '''
          利用简单工厂的概念,综合管理对应的请求方法
          :param method: 
          :return: 
          '''
          Method = method.lower()
          func = self.__getattribute__(Method)
          return func

     def __getattr__(self, item):
          raise ValueError('method error!')

     def post(self, url="", data=None, headers=None) ->Request:
          return self.session.request(method="post", url=self.base_url+url, data=data, headers=headers)

     def get(self, url="", data=None, headers=None) ->Request:
          return self.session.request(method="get", url=self.base_url+url, params=data, headers=headers)

if __name__=="__main__":
     a = RestfulApi("www.baidu.com")
     result = (a.send("get"))(data=None)
     print(result.text)

初步结合Pytest和requests

数据驱动概念

接口自动化测试,无非是同样的逻辑,发起请求,断言响应内容,参数化所需数据,然后进行下一个用例的执行。所以代码都是一样的,重复创建多个用例代码是一件枯燥且无味的事情。所以就提出了数据驱动概念,用一套代码只改变数据来执行。在pytest中,实现该概念的核心方法就是pytest.mark.parametrize()

pytest.mark.parametrize()

该方法所需的参数核心是2个:argnames、argvalues

argnames:指你所需要驱动的数据这个变量名,该名放到对应的用例参数内即可执行对应所要驱动的数据

argvalues: 指你所数据驱动的数据,常见的数据形式为列表

class Test_1():
     @pytest.mark.parametrize('demo', [{'url': 'www.baidu.com',
                                        "method": "get",
                                        "data": None}, {'url': 'www.hao123.com',
                                        "method": "get",
                                        "data": None}])
     def test_request(self, demo):
最终结合
# -*- coding: utf-8 -*-
# @Author : Ryhn
import pytest
from common.api.RestfulApi import RestfulApi


class Test_1():
     @pytest.mark.parametrize('demo', [{'url': 'www.baidu.com',
                                        "method": "get",
                                        "data": None}, {'url': 'www.hao123.com',
                                        "method": "get",
                                        "data": None}])
     def test_request(self, demo):
          a = RestfulApi(demo['url'])
          result = (a.send(demo['method']))(data=demo['data'])
          print(result.text)

  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值