zoukankan      html  css  js  c++  java
  • HttpRunner3源码阅读:2. 模型定义

    models.py

    昨天体验的时候我们分别执行了httprunner -h,httprunner startproject demo, httprunner run demo,但是源码中其调用了其他文件中的方法所以暂时先不分析cli.py了,先从根本开始models.py

    可用资料

    typing[类型提示]: https://docs.python.org/zh-cn/3/library/typing.html
    pydantic[类型校验]: https://pydantic-docs.helpmanual.io/
    用上这两个库就有点强类型语言的味儿了
    泛型: https://docs.python.org/zh-cn/3/library/typing.html#generics
    枚举: https://docs.python.org/zh-cn/3/library/enum.html

    导包分析

    import os   # 系统包
    from enum import Enum   # 枚举类
    from typing import Any  # Any 表示 任意类型
    from typing import Dict # dict 的泛型版本。
    from typing import Text # Text 是 str 的别名
    from typing import Union # 联合类型;Union[X, Y] 的意思是,非 X 即 Y
    from typing import Callable # 可调类型; Callable[[int], str] 是把(int)转为 str 的函数。
    from typing import List # list 的泛型版本。
    from pydantic import BaseModel  # pydantic定义对象的基类
    from pydantic import Field    # pydantic 中 字段扩展定义
    from pydantic import HttpUrl  # 校验url地址的
    

    类型别名定义

    该系列中个人对类型的看法/叫法如下

    1. Text => str / 文本
    2. List => list / 列表
    3. Dict => dict / 字典
    Name = Text     # Name 的本质 其实就是 Text(Text 本质又是 str)
    Url = Text
    BaseUrl = Union[HttpUrl, Text]  # 是url 或者 Text 两者之一
    VariablesMapping = Dict[Text, Any] # key 是 Text ,value 是任意类型
    FunctionsMapping = Dict[Text, Callable] # key 是 Text, value是可调用对象
    Headers = Dict[Text, Text]  # key 是 str, value 也是 str
    Cookies = Dict[Text, Text] # 同上
    Verify = bool   # 布尔类型
    Hooks = List[Union[Text, Dict[Text, Text]]] # 列表,列表中的元素是 str 或者 key,value 都是 str
    Export = List[Text]  # 列表,列表中元素是 str
    Validators = List[Dict] # 列表,列表中元素是 字典
    Env = Dict[Text, Any]  # 字典 key 是 str, value 是任意类型
    

    请求方法

    # 枚举类,其中属性是 Text类型
    class MethodEnum(Text, Enum):
        GET = "GET"
        POST = "POST"
        PUT = "PUT"
        DELETE = "DELETE"
        HEAD = "HEAD"
        OPTIONS = "OPTIONS"
        PATCH = "PATCH"
    

    其余模型

    避免篇幅过长,这里直接复制源代码 附上注释

    class TConfig(BaseModel):
        """测试配置模型"""
        name: Name
        verify: Verify = False
        base_url: BaseUrl = ""
        # Text: prepare variables in debugtalk.py, ${gen_variables()}
        # 变量
        variables: Union[VariablesMapping, Text] = {}
        parameters: Union[VariablesMapping, Text] = {}
        # setup_hooks: Hooks = []
        # teardown_hooks: Hooks = []
        export: Export = []
        path: Text = None
        weight: int = 1
    
    
    class TRequest(BaseModel):
        """测试请求模型"""
        """requests.Request model"""
    
        method: MethodEnum  # 这里的类型是前面定义的请求方法枚举
        url: Url  
        # 查询参数
        params: Dict[Text, Text] = {}
        headers: Headers = {}
        # alias 是别名, json 数据
        req_json: Union[Dict, List, Text] = Field(None, alias="json")
        # data 数据 - 表单
        data: Union[Text, Dict[Text, Any]] = None
        cookies: Cookies = {}
        timeout: float = 120
        # 允许重定向
        allow_redirects: bool = True
        # 安全验证
        verify: Verify = False
        upload: Dict = {}  # used for upload files
    
    
    class TStep(BaseModel):
        """测试步骤模型"""
        name: Name
        # 步骤可以是一个请求模型
        request: Union[TRequest, None] = None
        # 用例
        testcase: Union[Text, Callable, None] = None
        # 变量
        variables: VariablesMapping = {}
        setup_hooks: Hooks = []
        teardown_hooks: Hooks = []
        # used to extract request's response field
        # 提取响应字段
        extract: VariablesMapping = {}
        # used to export session variables from referenced testcase
        # 导出字段
        export: Export = []
        # 验证器
        validators: Validators = Field([], alias="validate")
        # 验证脚本
        validate_script: List[Text] = []
    
    
    class TestCase(BaseModel):
        """测试用例模型 = 测试配置 + 测试步骤"""
        config: TConfig
        teststeps: List[TStep]
    
    
    class ProjectMeta(BaseModel):
        """项目配置模型"""
        # debugtalk.py 文件内容
        debugtalk_py: Text = ""  # debugtalk.py file content
        debugtalk_path: Text = ""  # debugtalk.py file path
        # .env 文件路径
        dot_env_path: Text = ""  # .env file path
        # 在 debugtalk.py 中定义的函数
        functions: FunctionsMapping = {}  # functions defined in debugtalk.py
        env: Env = {}
        # 项目根目录
        RootDir: Text = os.getcwd()  # project root directory (ensure absolute), the path debugtalk.py located
    
    
    class TestsMapping(BaseModel):
        """测试集合"""
        project_meta: ProjectMeta
        testcases: List[TestCase]
    
    
    class TestCaseTime(BaseModel):
        """测试用例时间"""
        start_at: float = 0
        start_at_iso_format: Text = ""
        duration: float = 0
    
    
    class TestCaseInOut(BaseModel):
        """测试用例输入输出"""
        # 输入参数
        config_vars: VariablesMapping = {}
        # 导出参数
        export_vars: Dict = {}
    
    
    class RequestStat(BaseModel):
        """请求状态"""
        content_size: float = 0
        response_time_ms: float = 0
        elapsed_ms: float = 0
    
    
    class AddressData(BaseModel):
        """地址数据"""
        client_ip: Text = "N/A"
        client_port: int = 0
        server_ip: Text = "N/A"
        server_port: int = 0
    
    
    class RequestData(BaseModel):
        """请求数据模型"""
        method: MethodEnum = MethodEnum.GET
        url: Url
        headers: Headers = {}
        cookies: Cookies = {}
        body: Union[Text, bytes, List, Dict, None] = {}
    
    
    class ResponseData(BaseModel):
        """响应数据模型"""
        status_code: int
        headers: Dict
        cookies: Cookies
        encoding: Union[Text, None] = None
        content_type: Text
        body: Union[Text, bytes, List, Dict]
    
    
    class ReqRespData(BaseModel):
        """请求响应数据模型"""
        request: RequestData
        response: ResponseData
    
    
    class SessionData(BaseModel):
        """会话数据"""
        """request session data, including request, response, validators and stat data"""
    
        success: bool = False
        # in most cases, req_resps only contains one request & response
        # while when 30X redirect occurs, req_resps will contain multiple request & response
        req_resps: List[ReqRespData] = []
        stat: RequestStat = RequestStat()
        address: AddressData = AddressData()
        validators: Dict = {}
    
    
    class StepData(BaseModel):
        """步骤数据模型"""
        """teststep data, each step maybe corresponding to one request or one testcase"""
    
        success: bool = False
        name: Text = ""  # teststep name
        data: Union[SessionData, List['StepData']] = None
        export_vars: VariablesMapping = {}
    
            
    StepData.update_forward_refs()
    
    
    class TestCaseSummary(BaseModel):
        """测试用例结果"""
        name: Text
        success: bool
        case_id: Text
        time: TestCaseTime
        in_out: TestCaseInOut = {}
        log: Text = ""
        step_datas: List[StepData] = []
    
    
    class PlatformInfo(BaseModel):
        httprunner_version: Text
        python_version: Text
        platform: Text
    
    
    class TestCaseRef(BaseModel):
        name: Text
        base_url: Text = ""
        testcase: Text
        variables: VariablesMapping = {}
    
    
    class TestSuite(BaseModel):
        """测试套件"""
        config: TConfig
        testcases: List[TestCaseRef]
    
    
    class Stat(BaseModel):
        """结果集状态"""
        total: int = 0
        success: int = 0
        fail: int = 0
    
    
    class TestSuiteSummary(BaseModel):
        """测试套件结果收集"""
        success: bool = False
        stat: Stat = Stat()
        time: TestCaseTime = TestCaseTime()
        platform: PlatformInfo
        testcases: List[TestCaseSummary]
    

    最后

    上述内容个人理解,如有错误欢迎指出交流。

    作者:zy7y
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。
  • 相关阅读:
    iOS中图片与视频一次性多选
    UIImagePickerController Class
    1月16日
    10月20日
    1月14日
    1月13日
    1月12日
    1月11日
    课程评价与建议
    加分总结
  • 原文地址:https://www.cnblogs.com/zy7y/p/15093604.html
Copyright © 2011-2022 走看看