mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-04 23:16:57 +08:00
feat: use pydantic to implement testcase schema
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
from httprunner import __version__
|
from httprunner import __version__
|
||||||
from .routers import deps, debugtalk, testcase
|
from .routers import deps, debugtalk, debug
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
|
|
||||||
@@ -19,4 +19,4 @@ async def get_hrun_version():
|
|||||||
|
|
||||||
app.include_router(deps.router)
|
app.include_router(deps.router)
|
||||||
app.include_router(debugtalk.router)
|
app.include_router(debugtalk.router)
|
||||||
app.include_router(testcase.router)
|
app.include_router(debug.router)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ def stdout_io(stdout=None):
|
|||||||
sys.stdout = old
|
sys.stdout = old
|
||||||
|
|
||||||
|
|
||||||
@router.post("/hrun/debug/debugtalk", tags=["debugtalk"])
|
@router.post("/hrun/debug/debugtalk_py", tags=["debugtalk"])
|
||||||
async def debug_python(request: Request):
|
async def debug_python(request: Request):
|
||||||
body = await request.body()
|
body = await request.body()
|
||||||
|
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
from fastapi import APIRouter
|
|
||||||
|
|
||||||
from httprunner.api import HttpRunner
|
|
||||||
|
|
||||||
router = APIRouter()
|
|
||||||
runner = HttpRunner()
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/hrun/debug/api", tags=["testcase"])
|
|
||||||
async def debug_single_api():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/hrun/debug/testcase", tags=["testcase"])
|
|
||||||
async def debug_single_testcase():
|
|
||||||
resp = {
|
|
||||||
"code": 0,
|
|
||||||
"message": "success",
|
|
||||||
"result": {}
|
|
||||||
}
|
|
||||||
testcases = [
|
|
||||||
{
|
|
||||||
"config": {
|
|
||||||
'name': "post data",
|
|
||||||
'variables': {
|
|
||||||
"var1": "abc",
|
|
||||||
"var2": "def"
|
|
||||||
},
|
|
||||||
"export": ["status_code", "req_data"]
|
|
||||||
},
|
|
||||||
"teststeps": [
|
|
||||||
{
|
|
||||||
"name": "post data",
|
|
||||||
"request": {
|
|
||||||
"url": "http://httpbin.org/post",
|
|
||||||
"method": "POST",
|
|
||||||
"headers": {
|
|
||||||
"User-Agent": "python-requests/2.18.4",
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
"data": "$var1"
|
|
||||||
},
|
|
||||||
"extract": {
|
|
||||||
"status_code": "status_code",
|
|
||||||
"req_data": "content.data"
|
|
||||||
},
|
|
||||||
"validate": [
|
|
||||||
{"eq": ["status_code", 201]}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
tests_mapping = {
|
|
||||||
"testcases": testcases
|
|
||||||
}
|
|
||||||
summary = runner.run_tests(tests_mapping)
|
|
||||||
if not summary["success"]:
|
|
||||||
resp["code"] = 1
|
|
||||||
resp["message"] = "fail"
|
|
||||||
|
|
||||||
resp["result"] = summary
|
|
||||||
return resp
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .testcase import ProjectMeta, TestCase, TestCases
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from httprunner.schema import common
|
||||||
|
|
||||||
|
|
||||||
|
class Api(BaseModel):
|
||||||
|
name: common.Name
|
||||||
|
request: common.Request
|
||||||
|
variables: common.Variables
|
||||||
|
base_url: common.BaseUrl
|
||||||
|
setup_hooks: common.Hook
|
||||||
|
teardown_hooks: common.Hook
|
||||||
|
extract: common.Extract
|
||||||
|
validate: common.Validate
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
from enum import Enum
|
||||||
|
from typing import Dict, List, Any, Tuple
|
||||||
|
|
||||||
|
from pydantic import BaseModel, HttpUrl, Field
|
||||||
|
|
||||||
|
Name = str
|
||||||
|
Url = HttpUrl
|
||||||
|
BaseUrl = str
|
||||||
|
Variables = Dict[str, Any]
|
||||||
|
Headers = Dict[str, str]
|
||||||
|
Verify = bool
|
||||||
|
Hook = List[str]
|
||||||
|
Export = List[str]
|
||||||
|
Extract = Dict[str, str]
|
||||||
|
Validate = List[Dict[str, Tuple[str, Any]]]
|
||||||
|
Env = Dict[str, Any]
|
||||||
|
|
||||||
|
|
||||||
|
class MethodEnum(str, Enum):
|
||||||
|
GET = 'GET'
|
||||||
|
POST = 'POST'
|
||||||
|
PUT = "PUT"
|
||||||
|
DELETE = "DELETE"
|
||||||
|
HEAD = "HEAD"
|
||||||
|
OPTIONS = "OPTIONS"
|
||||||
|
PATCH = "PATCH"
|
||||||
|
CONNECT = "CONNECT"
|
||||||
|
TRACE = "TRACE"
|
||||||
|
|
||||||
|
|
||||||
|
class TestsConfig(BaseModel):
|
||||||
|
name: Name
|
||||||
|
verify: Verify = False
|
||||||
|
base_url: BaseUrl = ""
|
||||||
|
variables: Variables = {}
|
||||||
|
setup_hooks: Hook = []
|
||||||
|
teardown_hooks: Hook = []
|
||||||
|
export: Export = []
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
schema_extra = {
|
||||||
|
"examples": [
|
||||||
|
{
|
||||||
|
"name": "used in testcase/testsuite to configure common fields",
|
||||||
|
"verify": False,
|
||||||
|
"base_url": "https://httpbin.org"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Request(BaseModel):
|
||||||
|
method: MethodEnum = MethodEnum.GET
|
||||||
|
url: Url
|
||||||
|
params: Dict[str, str] = {}
|
||||||
|
headers: Headers = {}
|
||||||
|
req_json: Dict = Field({}, alias="json")
|
||||||
|
cookies: Dict[str, str] = {}
|
||||||
|
timeout: int = 120
|
||||||
|
allow_redirects: bool = True
|
||||||
|
verify: Verify = False
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
from typing import Dict, List, Text
|
||||||
|
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from httprunner.schema import common
|
||||||
|
|
||||||
|
|
||||||
|
class ProjectMeta(BaseModel):
|
||||||
|
debugtalk_py: Text = ""
|
||||||
|
variables: common.Variables = {}
|
||||||
|
env: common.Env = {}
|
||||||
|
|
||||||
|
|
||||||
|
class TestStep(BaseModel):
|
||||||
|
name: common.Name
|
||||||
|
request: common.Request
|
||||||
|
extract: Dict[str, str] = {}
|
||||||
|
validation: common.Validate = Field([], alias="validate")
|
||||||
|
|
||||||
|
|
||||||
|
class TestCase(BaseModel):
|
||||||
|
config: common.TestsConfig
|
||||||
|
teststeps: List[TestStep]
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
schema_extra = {
|
||||||
|
"examples": [
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"name": "testcase name"
|
||||||
|
},
|
||||||
|
"teststeps": [
|
||||||
|
{
|
||||||
|
"name": "api 1",
|
||||||
|
"api": "/path/to/api1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "api 2",
|
||||||
|
"api": "/path/to/api2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"name": "demo testcase",
|
||||||
|
"variables": {
|
||||||
|
"device_sn": "ABC",
|
||||||
|
"username": "${ENV(USERNAME)}",
|
||||||
|
"password": "${ENV(PASSWORD)}"
|
||||||
|
},
|
||||||
|
"base_url": "http://127.0.0.1:5000"
|
||||||
|
},
|
||||||
|
"teststeps": [
|
||||||
|
{
|
||||||
|
"name": "demo step 1",
|
||||||
|
"api": "path/to/api1.yml",
|
||||||
|
"variables": {
|
||||||
|
"user_agent": "iOS/10.3",
|
||||||
|
"device_sn": "$device_sn"
|
||||||
|
},
|
||||||
|
"extract": [
|
||||||
|
{
|
||||||
|
"token": "content.token"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validate": [
|
||||||
|
{
|
||||||
|
"eq": ["status_code", 200]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "demo step 2",
|
||||||
|
"api": "path/to/api2.yml",
|
||||||
|
"variables": {
|
||||||
|
"token": "$token"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TestCases = List[TestCase]
|
||||||
@@ -40,6 +40,7 @@ filetype = "^1.0.5"
|
|||||||
jsonpath = "^0.82"
|
jsonpath = "^0.82"
|
||||||
sentry-sdk = "^0.13.5"
|
sentry-sdk = "^0.13.5"
|
||||||
jsonschema = "^3.2.0"
|
jsonschema = "^3.2.0"
|
||||||
|
pydantic = "^1.4"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
flask = "<1.0.0"
|
flask = "<1.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user