当前位置: 首页 > 工具软件 > Pydantic > 使用案例 >

使用pydantic进行接口校验

朱祺
2023-12-01

背景

在进行接口自动化测试的时候,只是校验「状态码」或者「部分字段」并不能很好的发现问题,有时候需要对字段的类型,关系进行校验。

之前尝试过使用JSON Schema来进行校验,但是语法上感觉比较变扭。这次尝试使用pydantic来进行校验

pydantic

https://pydantic-docs.helpmanual.io/

pydantic:使用 python 类型注释进行数据验证和设置管理。

安装

$ pip install pydantic

实例

请求接口

最近在测试一个「订单合流」的接口

该接口可以查询制定类型的订单

总共有19个类型的订单,用一个字典处理它的对应关系

biz_type_data = {
    1: "预约挂号",
    2: "问诊",
    3: "服务包",
    4: "追问包",
    5: "一病多问",
    6: "会员",
    7: "体检",
    8: "远程医疗",
    9: "处方",
    10: "专病",
    11: "商品",
    12: "处方药品",
    13: "会员拼团",
    14: "讲堂课程",
    15: "健康管家",
    16: "赞赏",
    17: "停诊保障",
    18: "检查检验",
    19: "心理体检",
}

该接口的请求参数为

data = {"q": "", "pageNo": 1, "pageSize": 10, "bizOrderTypes": [1]}

修改「bizOrderTypes」列表即可返回对应类型的订单

比如[1]就是返回「预约挂号」的订单

返回的内容类似:

{
  "code": "0",
  "flag": "0",
  "message": "成功",
  "retUrl": "",
  "pageNo": 1,
  "pageSize": 1000,
  "pageCount": 1,
  "recordCount": 20,
  "items": [
    {
      "bizNo": "202111171045333625",
      "bizCode": "",
      "bizName": "",
      "bizOrderType": 1,
      "bizOrderTypeName": "预约挂号",
      "bizType": 1,
      "bizTypeName": "普通预约单",
      "title": "",
      "num": 1,
      "dealAmount": 1,
      "bizStatus": 3,
      "bizStatusName": "待确认",
      "providerName": "",
      "gmtBizCreated": 1637311540000,
      "props": {
        "patientName": "钟鑫",
        "deptName": "神经外科",
        "docName": "卢来元懿",
        "insure": 0,
        "visitDate": 1637337600000,
        "docTitle": "国家专家",
        "hospitalName": "微医门诊部"
      }
    },
    {
      "bizNo": "202111171045333406",
      "bizCode": "",
      "bizName": "",
      "bizOrderType": 1,
      "bizOrderTypeName": "预约挂号",
      "bizType": 1,
      "bizTypeName": "普通预约单",
      "title": "",
      "num": 1,
      "dealAmount": 1000,
      "bizStatus": 2,
      "bizStatusName": "待就诊",
      "providerName": "",
      "gmtBizCreated": 1637311475000,
      "props": {
        "patientName": "钟鑫",
        "deptName": "妇科",
        "docName": "王涛",
        "insure": 0,
        "visitDate": 1637683200000,
        "docTitle": "主任医师",
        "hospitalName": "徐州市中医院"
      }
    }
  ],
  "errorInfo": "成功"
}

导入包

from typing import Union, List
from pydantic import BaseModel, validator
from datetime import date

编写类型校验

由于外部的内容是通用的页面处理,所以我们主要校验item中的内容

class new_order_list(BaseModel):
    bizNo: str
    bizCode: str = ""
    bizName: str = ""
    bizOrderType: int
    bizOrderTypeName: str
    bizType: int
    bizTypeName: str
    title: str = ""
    num: int
    dealAmount: int
    bizStatus: int
    bizStatusName: str
    providerName: str = ""
    gmtBizCreated: date
    props: dict
  • str表示内容应该为字符串

  • str = ""表示内容应该为字符串且默认为空

  • int表示内容应该为数字

  • dict表示内容应该为字典

  • data表示时间

Pydantic支持以下日期时间 类型:

  • datetime 字段可以是:

  • datetime, 现有datetime对象

  • intfloat,假定为 Unix 时间,即自 1970 年 1 月 1 日以来的秒数(如果 >=-2e10或 <= `2e10`)或毫秒(如果 <`-2e10`或 > 2e10

  • str,以下格式有效:

    • YYYY-MM-DD[T]HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]

    • intfloat作为字符串(假设为 Unix 时间)

  • date 字段可以是:

  • date, 现有date对象

  • int或者float,见datetime

  • str,以下格式有效:

    • YYYY-MM-DD

    • int或者float,见datetime

  • time 字段可以是:

  • time, 现有time对象

  • str,以下格式有效:

    • HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]

  • timedelta 字段可以是:

  • timedelta, 现有timedelta对象

  • int或者float,假设为秒

  • str,以下格式有效:

    • [-][DD ][HH:MM]SS[.ffffff]

    • [±]P[DD]DT[HH]H[MM]M[SS]S (timedelta 的 ISO 8601 格式)

由于props不同订单返回的字典不一样,所以我们后面封装另一个类去校验它

编写内部逻辑校验

对于某些字段有专门的逻辑,所以我们编写一个biz_type_match函数去校验

@validator('bizType')
    def biz_type_match(cls, v, values, **kwargs):
        if "bizOrderType" in values and "bizTypeName" in values:
            if values["bizOrderType"] == 1:
                reg_type_name = ["普通预约单", "专病预约单"]
                if reg_type_name[v - 1] != values["bizTypeName"]:
                    raise ValueError('bizType与bizTypeName不一致')
        return v

这个函数中v表示装饰器装饰的内容,也就是bizType

values表示的返回的整个内容

所以我们就可以校验「bizTypeName」和「bizType」的对应关系了

编写子字典props校验

class bizType():
    class bizType1(BaseModel):
        """
        预约挂号
        """
    deptName: str  # 科室名称
    patientName: Union[str, None]  # 患者姓名 就诊人可以解绑,所以允许为空
    docName: str  # 医生姓名
    docTitle: str  # 医生职称
    visitDate: date  # 就诊日期时间戳
    hospitalName: str  # 医院名称
    insure: int  # 是否购买停诊保险 0否1是
  • Union表示运行多个类型,可以根据具体逻辑设计

使用

for i in response_data['items']:
    new_order_list(**i)
    obj = getattr(bizType, f'bizType{type_data[0]}')
    try:
        obj(**i['props'])
    except Exception as e:
        pytest.assume(False, f"Error:{e}")

将拿到的数据传入对应的类中,就会自动进行校验

其他

更多校验方式可以参考官网:https://pydantic-docs.helpmanual.io/

 类似资料: