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地址的
型別別名定義
該系列中個人對型別的看法/叫法如下
- Text => str / 文字
- List => list / 列表
- 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]
最後
上述內容個人理解,如有錯誤歡迎指出交流。