python+requests+pytest实现接口自动化测试

前言

  • 运用框架:requests,pytest

封装requests和断言方法

 1、新建py文件requests_,文件名称自定
 2、封装分3个阶段,
   封装控制台打印网络请求信息和返回信息
   封装requests网络请求,已post请求为主
   重新封装断言方法

improt json
from requests import Request

""" 1、封装控制台打印网络请求信息和返回信息 """
# 控制台带引网络请求信息
def print_req(preq):
    print('=======================【请求信息】=======================')
    print(f'【url】-{preq.method}{preq.url}')
    print(f'【headers】-{preq.headers}')
    print(f'【data】-{preq.body}')
# 控制台打印网络返回结果
def print_resp(resp):
    print('=======================【返回结果】=======================')
    print(f'【status_code】-{resp.status_code}')
    print(resp.json()) # 不美化打印返回数据
    ppd(resp.json()) # 美化打印字典格式数据
    print('========================================================')
# 美化打印字典格式数据
def ppd(dic):
    print(json.dumps(dic,indent=2,ensure_ascii=False))
    
""" 2、封装requests网络请求 """
# 发送网络请求,返回原始response对象
def pure_request(s,url,data='{}',headers={'Content-type':'application/json'}):
    req = Request('POST',url,data=data,headers=headers)
    prep = req.prepare() # 准备url
    print_req(prep) # 调用上面封装好的控制台打印方法,打印请求信息
    
    # 发送网络请求,返回请求结果
    resp = s.send(prep)
    print_resp(resp) # 调用上面封装好的控制台打印方法,打印返回信息
    return resp
# 发送网络请求,返回json对象
def request(s,url,data='{}',headers={'Content-type':'application/json'}):
    result = pure_request(s,url,json.dumps(data),headers)
    return result.json()    

""" 3.重新封装json格式断言方法 """
"""
    d1-预期结果,d2-实际返回结果
    递归d2字典是不是和d1模板字典所期望值
    d1中 键开头是 !,那么 d1 != d2
    d1中 键开头是 * ,那么表示这个key不应该存在
    d1中 键开头是 ?,可选字段,有的话进行验证,没有的略过
    d1中 键开头是 @ ,那么检查长度是否正确
    d1中 键开头是 [] ,那么检查只是否在一个范围内,例如[1,2,3,4]
    d1中 值是None, 只检查是否有这个键
    d1中 值不是None, 检查两个值是否一模一样
"""
def iterdict_dic(d1,d2):
    # 判断数据类型是否一样
    if type(d1) != type(d2):
        return False,f"数据类型不同 {d1}={type(d1)},{d2}={type(d2)}"
    # 判断字典内key和values是否期望值
    for k,v in d1.items():
        opposite = False # 取反操作符
        if k[0] == '*': # 如果键的开头是*,那么表示键在实际值中不应该存在
            k = k[1:] # 取键的实际值
            if k in d2:
                return False,f'多余字段:{k}'
        elif k[0] == '@': # 如果键的开头是@,那么values的长度和实际值应相等
            k = k[1:]
            if k not in d2:
                return False,f'缺少字段:{k}'
            if len(v) != len(d2[k]):
                return False,f'[{k}]的长度是:{len(v)},实际长度:{len(d2[k])}'
        elif k[:2] == '[]': # 如果键的开头是[],那么实际值需要在预期值得范围内,比如实际值是1,预期值是[1,2,3]那么返回True
            k = k[2:]
            if k not in d2:
                return False,f'缺少字段:{k}'
            if d2[k] not in v:
                return False,f"[{k}]的值是:{d2[k]},不在期望值内[{v}]"
        elif k[0] == "?":
            k = k[1:]
            if k not in d2:
                continue
        elif k[0] == "!"
            k = k[1:]
            opposite = True
                                                                        
        if k not in d2:
            return False,f"缺少必要字段:[{k}]"
        if v == Nonecontinue # 如果values等于None,跳过
        if isinstance(v,dict):
            res,msg = iterdict_(v,d2[k])
            if ret == False:
                return ret,msg
        elif isinstance(v,list):
            if not isinstance(d2[k],list):
                return False,f"[{d2[k]}]是:{type(d2[k])},不是一个数组"
            if len(v) > len(d2[k]):
                return False,f"[{v}]长度和实际值:{d2[k]}长度不同"
            for i in range(0,len(v)):
                ret,msg = iterdict_(v[i],d2[k][i])
                if ret == False:
                    return ret,msg
        elif opposite:
            if v == d2[k]:
                return False,f"[{k}]的值不应该等于[{v}]"
        else:
            if v != d2[k]:
                return False,f"[{k}]的期望值:[{v}] != 实际值:[{d2[k]}]"
        
     return True,""                                                                                                                                                                                                                                                                                                                                                           
                        
def iterdict_(d1,d2):
    if type(d1) != type(d2):
        return False,f"数据类型不同 {d1}={type(d1)},{d2}={type(d2)}"
         
    # isinstance-主要用来判断变量是否属于某个内建类型,对象的类型与参数二的类型相同则返回True,否则返回False
    if isinstance(d1,dict): # 如果预期值是字典格式则返回上面封装好的方法做判断                             
        return iterdict_dic(d1,d2)
    elif isinstance(d1,list): #如果预期值是列表格式则走下面方法
        if len(d1) > len(d2):
            return False,"列表长度不相等"
        # 循环列表断言列表值
        for i in range(0,len(d1)):
            ret,msg = iterdict_(d1[i],d2[i]) # 判断预期值是否等于实际值 
            if ret == False:
                return ret,msg
            return True,""
     else:
        if d1 != d2:
            return False,"预期值-[{d1}] != 实际值-[{d2}]" # 判断预期值是否等于实际值 
         else:
            return True,""                                                                                           

# 最后调用断言方法
def iterdict(d1,d2):
    ret,msg = iterdict_(d1,d2)
    assert ret,msg

 3、测试封装的requests_方法是否达到预期
   1.新建文件test_iterdict
   2.测试request网络请求方法,可用自家公司接口测试

python+requests+pytest实现接口自动化测试_第1张图片
   【Terminal】控制台输入pytest -s test_iterdict.py即可运行以test开头或结尾的用例,可在控制台打印接口请求的详细信息
python+requests+pytest实现接口自动化测试_第2张图片
4、测试iterdict断言方法,(挑几个演示一下,有兴趣的可以自行调试)
   预期值d1都出现在实际值d2中
python+requests+pytest实现接口自动化测试_第3张图片
   d2中缺少字段python+requests+pytest实现接口自动化测试_第4张图片
   d1中值和d2实际值不相等python+requests+pytest实现接口自动化测试_第5张图片
   d1中值等于None则值判断键是否存在python+requests+pytest实现接口自动化测试_第6张图片
   键前面是?实际值中没有则跳过python+requests+pytest实现接口自动化测试_第7张图片
   键前面是?实际值中出现则验证
python+requests+pytest实现接口自动化测试_第8张图片

 


编写接口测试用例,使用pytest运行用例

  • pytest-文件名、函数名要以test_开头或以_test结尾,类名以Test开头或结尾,控制台输入pytest -s 文件名
    即会运行文件中以test为名的用例类或函数,更多pytest知识可看官方文档;

 1、不方便用公司接口做演示,自己写了一个简易的小接口来编写一下测试用例,然后启动服务就可以本机调用测试接口

from flask import Flask,request

app = Flask(__name__)

"""
    /api_test 接口路径
    请求参数:user:liuage    pwd:123456
    正常请求-返回值:{'rc':1,'msg':'登录成功'}
    异常请求-返回值:{'rc':999,'msg':'异常情况'}   
"""

@app.route('/api_test',methods=['GET','POST'])
def login_api():
    if request.method == "POST":
        data = eval(request.data)
        if 'user' not in data:
            return {'rc':-999,'msg':'账号不能为空'}
        if 'pwd' not in data:
            return {'rc':-999,'msg':'密码不能为空'}
        user = data['user']
        pwd = data['pwd']

        if user != 'liuage':
            return {'rc':-999,'msg':'请输入正确账号'}
        elif pwd != 123456:
            return {'rc':-999,'msg':'请输入正确密码'}
        else:
            return {'rc': 1, 'msg': '登录成功'}
    else:
        return {'rc':-999}

if __name__ == '__main__':
    # ip地址填自己电脑的IP地址,如:192.168.2.3
    app.run('自己电脑IP地址',debug=True)

 2、编写接口测试用例

from study.api_test import requests_
from requests import Session

s = Session()

class Test_login():

    def setup_class(self):
        self.url = "http://192.168.22.50:5000/api_test"
        # 请求参数
        self.payload = {
            "user" : "liuage",
            "pwd" : 123456
        }

    # 测试接口正常请求情况
    def test_normal(self):
        # 调用网络请求
        result = requests_.request(s,self.url,self.payload)

        # 填入预期值
        fields = {
            "rc" : 1,
            "msg" : '登录成功'
        }

        # 断言返回值
        requests_.iterdict(fields,result)

    # 测试账号错误情况
    def test_account_error(self):
        payload = {
            'user' : '111',
            'pwd' : 123456
        }
        result = requests_.request(s,self.url,payload)

        fields = {
            'msg' : '请输入正确账号',
            'rc' : -999
        }
        requests_.iterdict(fields,result)

    # 测试密码错误情况
    def test_pwd_error(self):
        payload = {
            'user':'liuage',
            'pwd' : 12345
        }
        result = requests_.request(s,self.url,payload)

        fields = {
            'rc' : -999,
            'msg' : '请输入正确密码'
        }
        requests_.iterdict(fields,result)

    # 测试账号为空情况
    def test_not_account(self):
        payload = {'pwd':''}
        result = requests_.request(s,self.url,payload)
        fields = {'rc':-999,'msg':'账号不能为空'}
        requests_.iterdict(fields,result)

 3、【Terminal】终端输入pytest -s 用例文件名 运行用例python+requests+pytest实现接口自动化测试_第9张图片
  如果有一个用例没达到预期结果就会报错python+requests+pytest实现接口自动化测试_第10张图片


感谢观看

你可能感兴趣的:(python,自动化,python)