接口自动化框架关于接口关联的封装

나중에 / 2023-05-13 / 原文

一、类之间继承问题:

由于在test_api.py定义了全局变量,而test.user.py想使用这些全局变量就得导入test_api.py模块

但是因为test_user.py导入了test_api.py的模块并使用,到时候执行test_user.py的时候会把test.api.py中的方法(用例)也执行一遍

#演示:

目录结构:

test_api.py

import requests

class TestRequest():

    #全局变量,类变量,通过类名调用
    access_token=""
    sess=requests.session()  #定义全局变量sess=requests.session(),将所有的requests都替换为requests.session()就相当于都在一个会话中了

    # 获取接口统一鉴权码token
    def test_token(self):
        url = "http://47.108.153.47:8089/qzcsbj/user/login"
        shuju={
            "username": "ddance",
            "password": "000000"
        }
        res=TestRequest.sess.request(method="post",url=url,json=shuju)  #将所有的requests都替换为requests.session()就相当于都在一个会话中了
        print(res.json())
        TestRequest.access_token=res.json()["data"]["token"]  #将token的值赋给全局变量access_token

    #修改一个商品
    def test_edit_product(self):
        url = "http://47.108.153.47:8089/qzcsbj/product/update"
        shuju = {
            "product": {
                "id": 381,
                "price": 20,  #将价格改为20元
                "productName": "狗粮"
            },
            "token": TestRequest.access_token
        }
        res=TestRequest.sess.request(method="post",url=url,json=shuju)  #将所有的requests都替换为requests.session()就相当于都在一个会话中了
        print(res.json())

    #文件上传
    def test_file_upload(self):
        shuju = {
            "name": "01"
        }
        shuju1={
            "uploadfile":open(r"C:\01.jpg","rb"),  #r:转义 rb:转化为只读的二进制流
        }
        url = "http://47.108.153.47:8089/qzcsbj/file/upload?name=" + shuju["name"]  #接口文档中规定要将name的值跟在url之后,因此这里使用字典key提取name的值01拼接到url之后
        res=TestRequest.sess.request(method="post",url=url,json=shuju,files=shuju1)  #上传文件的时候使用files而不是data或者json  #将所有的requests都替换为requests.session()就相当于都在一个会话中了
        print(res.json())

test_user.py

import requests
from testcases.test_api import TestRequest  #导入testcases包下的test_api模块下的TestRequest类

class TestUser():
    
    #修改用户信息
    def test_edit_user(self):
        shuju={
            "token": TestRequest.access_token,  #使用TestRequest类的全局变量access_token
            "user": {
                "id": 1305,
                "username": "ddance",
                "password": "000000",
                "realName": "string",
                "sex": "0",
                "birthday": "2001-01-01",
                "phone": "13542588888",  #修改电话号码为13542588888
                "utype": "0",
                "addtime": "2023-05-12 22:21:56.0",
                "adduser": "ddance"
                }
        }
        url = "http://47.108.153.47:8089/qzcsbj/user/update"
        res=requests.request(method="post",url=url,json=shuju)
        print(res.json())

all.py

import pytest

if __name__ == '__main__':
    pytest.main()

执行结果:

D:\JetBrains\PycharmProjects\API接口测试\venv\Scripts\python.exe D:\JetBrains\PycharmProjects\API接口测试\all.py 
============================= test session starts =============================

testcases\test_api.py ...                                                [ 42%]  #这里3个“.”表示执行了3个用例
testcases\test_user.py ....                                              [100%]  #这里4个“.”表示执行了4个用例

============================== 7 passed in 0.93s ==============================

Process finished with exit code 0

为什么test_user.py中明明一个用例却执行了4个用例呢?这是因为test_user.py调用test_api.py下的类的时候把test_api.py类下的用例也执行了一遍

如何避免这种错误呢,可以去掉全局变量,用YAML文件代替保存解决:

#演示:

目录结构:#新增一个ymal空文件extract.yaml,使用yaml_util.py模块将test_api.py产生的全局变量access_token存储到extract.yaml,test_user.py在将extract.yaml中的内容提取使用

yaml_util.py

import yaml  #需要安装模块:pip install pyyaml
import os

#读取
def read_yaml(key):
    with open(os.getcwd()+'/extract.yaml',mode='r',encoding='utf-8') as f:  #os.getcwd()方法用于返回当前工作目录 #mode='a':追加|'w':覆盖|'r':只读 #encoding编码格式
        print('这里是打印'+os.getcwd()+'/extract.yaml')
        value=yaml.load(stream=f,Loader=yaml.FullLoader)  #yaml.load()读取yaml文件 #stream=f要读取的对象 #Loader=yaml.FullLoader全部提取
        return value[key]  #value是字典类型的,可以通过关键字方式输出值

#写入
def write_yaml(data):
    with open(os.getcwd()+'/extract.yaml',mode='a',encoding='utf-8') as f:
        yaml.dump(data,stream=f,allow_unicode=True)  #yaml.dump()写入数据到yaml文件 #allow_unicode=True允许unicode方式

#清空
def clear_yaml():
    with open(os.getcwd()+'/extract.yaml',mode='w',encoding='utf-8') as f:
        f.truncate()  #清空文件内容

test_api.py  #1、删除全局变量access_token  2、修改test_token用例中保存token的方式(存到文件中) 3、修改test_edit_product用例中获取token的方式(从文件中读取)

import requests
from common.yaml_util import read_yaml,write_yaml

class TestRequest():

    #全局变量,类变量,通过类名调用
    ##删除access_token=""
    sess=requests.session()  #定义全局变量sess=requests.session(),将所有的requests都替换为requests.session()就相当于都在一个会话中了

    # 获取接口统一鉴权码token
    def test_token(self):
        url = "http://47.108.153.47:8089/qzcsbj/user/login"
        shuju={
            "username": "ddance",
            "password": "000000"
        }
        res=TestRequest.sess.request(method="post",url=url,json=shuju)  #将所有的requests都替换为requests.session()就相当于都在一个会话中了
        print(res.json())
        #删除TestRequest.access_token=res.json()["data"]["token"]  #将token的值赋给全局变量access_token
        write_yaml({"access_token":res.json()["data"]["token"]})  #将{"access_token":token的值}键值对写入extract.yaml文件

    #修改一个商品
    def test_edit_product(self):
        url = "http://47.108.153.47:8089/qzcsbj/product/update"
        shuju = {
            "product": {
                "id": 381,
                "price": 20,  #将价格改为20元
                "productName": "狗粮"
            },
            #删除"token": TestRequest.access_token
            "token": read_yaml("access_token")  #读取extract.yaml文件中key为access_token对应的值
        }
        res=TestRequest.sess.request(method="post",url=url,json=shuju)  #将所有的requests都替换为requests.session()就相当于都在一个会话中了
        print(res.json())

    #文件上传
    def test_file_upload(self):
        shuju = {
            "name": "01"
        }
        shuju1={
            "uploadfile":open(r"C:\01.jpg","rb"),  #r:转义 rb:转化为只读的二进制流
        }
        url = "http://47.108.153.47:8089/qzcsbj/file/upload?name=" + shuju["name"]  #接口文档中规定要将name的值跟在url之后,因此这里使用字典key提取name的值01拼接到url之后
        res=TestRequest.sess.request(method="post",url=url,json=shuju,files=shuju1)  #上传文件的时候使用files而不是data或者json  #将所有的requests都替换为requests.session()就相当于都在一个会话中了
        print(res.json())

test_user.py  #1、删除导入test_api.py中全局变量的方法 2、修改test_edit_user用例中获取token的方式(从文件中读取)

import requests
#删除from testcases.test_api import TestRequest  #导入testcases包下的test_api模块下的TestRequest类
from common.yaml_util import read_yaml,write_yaml

class TestUser():

    #修改用户信息
    def test_edit_user(self):
        shuju={
            #删除"token": TestRequest.access_token,  #使用TestRequest类的全局变量access_token
            "token": read_yaml("access_token"),  #读取extract.yaml文件中key为access_token对应的值
            "user": {
                "id": 1305,
                "username": "ddance",
                "password": "000000",
                "realName": "string",
                "sex": "0",
                "birthday": "2001-01-01",
                "phone": "13542588888",  #修改电话号码为13542588888
                "utype": "0",
                "addtime": "2023-05-12 22:21:56.0",
                "adduser": "ddance"
                }
        }
        url = "http://47.108.153.47:8089/qzcsbj/user/update"
        res=requests.request(method="post",url=url,json=shuju)
        print(res.json())

all.py

import pytest

if __name__ == '__main__':
    pytest.main(['-vs'])

执行结果:

D:\JetBrains\PycharmProjects\API接口测试\venv\Scripts\python.exe D:\JetBrains\PycharmProjects\API接口测试\all.py 
============================= test session starts =============================

testcases/test_api.py::TestRequest::test_token {'code': 2003, 'msg': '登录成功', 'data': {'token': 'ddance_c08566ea-529b-4817-a8cf-edf20a3da6e8'}}
PASSED
testcases/test_api.py::TestRequest::test_edit_product {'code': 3005, 'msg': '更新商品成功', 'data': {'id': 381, 'productName': '狗粮', 'price': 20.0}}
PASSED
testcases/test_api.py::TestRequest::test_file_upload {'code': 7001, 'msg': '文件上传成功', 'data': '01_01.jpg_4d37c6cc-c3e1-4f46-9fa4-bfd9153a6e34.jpg'}
PASSED
testcases/test_user.py::TestUser::test_edit_user {'code': 2009, 'msg': '更新用户成功', 'data': {'id': 1305, 'username': 'ddance', 'password': '******', 'realName': 'string', 'sex': '0', 'birthday': '2001-01-01', 'phone': '13542588888', 'utype': '0', 'addtime': '2023-05-12 22:21:56.0', 'adduser': 'ddance'}}
PASSED

============================== 4 passed in 0.23s ==============================

Process finished with exit code 0

extract.yaml  #生成了一条token的值

access_token: ddance_c08566ea-529b-4817-a8cf-edf20a3da6e8

以上代码仍有问题,由于write.yaml()选择追加的方式写入数据,多次执行后extract.yaml文件中会有多个access_token:[value]键值对,到时候read.yaml()取值的时候可能会报错,解决办法是增加前后置方法在每次写入文件前清空extract.yaml文件

#演示:

目录结构:#增加前后置固件

conftest.py

import pytest
from common.yaml_util import write_yaml,read_yaml,clear_yaml

#在所有接口请求之前执行
@pytest.fixture(scope='package',autouse=True)  #作用域是包,即testcases目录,并且自动执行,其余文件无需任何修改
def clear_extract():
    clear_yaml()  #这是一个前置

如果test_user.py中用例需要test_api.py中用例的cookie怎么办呢?可以调用test_api.py中全局变量sess=requests.session()使两个文件中的用例处于同一个会话(session),但是这样同样会因为类之间继承的问题导致test_api.py被调用时再执行一次,怎么解决呢,可以使用统一请求封装