mirror of
https://github.com/httprunner/httprunner.git
synced 2026-08-29 03:57:22 +08:00
change: http client with pydantic models
This commit is contained in:
+17
-23
@@ -130,37 +130,32 @@ class HttpRunner(object):
|
|||||||
tests_results (list): list of testcase summary
|
tests_results (list): list of testcase summary
|
||||||
|
|
||||||
"""
|
"""
|
||||||
testsuite_summary = {
|
testsuite_summary = TestSuiteSummary(
|
||||||
"success": True,
|
success=True,
|
||||||
"stat": {
|
platform=report.get_platform(),
|
||||||
"total": len(tests_results),
|
testcases=[]
|
||||||
"success": 0,
|
)
|
||||||
"fail": 0
|
testsuite_summary.stat.total = len(tests_results)
|
||||||
},
|
testsuite_summary.stat.success = 0
|
||||||
"time": {},
|
testsuite_summary.stat.fail = 0
|
||||||
"platform": report.get_platform(),
|
|
||||||
"testcases": []
|
|
||||||
}
|
|
||||||
|
|
||||||
for testcase_summary in tests_results:
|
for testcase_summary in tests_results:
|
||||||
if testcase_summary.success:
|
if testcase_summary.success:
|
||||||
testsuite_summary["stat"]["success"] += 1
|
testsuite_summary.stat.success += 1
|
||||||
else:
|
else:
|
||||||
testsuite_summary["stat"]["fail"] += 1
|
testsuite_summary.stat.fail += 1
|
||||||
|
|
||||||
testsuite_summary["success"] &= testcase_summary.success
|
testsuite_summary.success &= testcase_summary.success
|
||||||
|
testsuite_summary.testcases.append(testcase_summary)
|
||||||
testsuite_summary["testcases"].append(testcase_summary)
|
|
||||||
|
|
||||||
total_duration = tests_results[-1].time.start_at + tests_results[-1].time.duration \
|
total_duration = tests_results[-1].time.start_at + tests_results[-1].time.duration \
|
||||||
- tests_results[0].time.start_at
|
- tests_results[0].time.start_at
|
||||||
testsuite_summary["time"] = {
|
|
||||||
"start_at": tests_results[0].time.start_at,
|
|
||||||
"start_at_iso_format": tests_results[0].time.start_at_iso_format,
|
|
||||||
"duration": total_duration
|
|
||||||
}
|
|
||||||
|
|
||||||
return TestSuiteSummary.parse_obj(testsuite_summary)
|
testsuite_summary.time.start_at = tests_results[0].time.start_at
|
||||||
|
testsuite_summary.time.start_at_iso_format = tests_results[0].time.start_at_iso_format
|
||||||
|
testsuite_summary.time.duration = total_duration
|
||||||
|
|
||||||
|
return testsuite_summary
|
||||||
|
|
||||||
def run_tests(self, tests_mapping) -> TestSuiteSummary:
|
def run_tests(self, tests_mapping) -> TestSuiteSummary:
|
||||||
""" run testcase/testsuite data
|
""" run testcase/testsuite data
|
||||||
@@ -188,7 +183,6 @@ class HttpRunner(object):
|
|||||||
|
|
||||||
# generate html report
|
# generate html report
|
||||||
self.exception_stage = "generate html report"
|
self.exception_stage = "generate html report"
|
||||||
report.stringify_summary(self._summary)
|
|
||||||
|
|
||||||
if self.save_tests:
|
if self.save_tests:
|
||||||
utils.dump_json_file(
|
utils.dump_json_file(
|
||||||
|
|||||||
+76
-102
@@ -7,81 +7,13 @@ from requests import Request, Response
|
|||||||
from requests.exceptions import (InvalidSchema, InvalidURL, MissingSchema,
|
from requests.exceptions import (InvalidSchema, InvalidURL, MissingSchema,
|
||||||
RequestException)
|
RequestException)
|
||||||
|
|
||||||
from httprunner import response
|
from httprunner.schema import RequestData, ResponseData
|
||||||
|
from httprunner.schema import SessionData, ReqRespData
|
||||||
from httprunner.utils import lower_dict_keys, omit_long_data
|
from httprunner.utils import lower_dict_keys, omit_long_data
|
||||||
from httprunner.schema import SessionData
|
|
||||||
|
|
||||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||||
|
|
||||||
|
|
||||||
def get_req_resp_record(resp_obj):
|
|
||||||
""" get request and response info from Response() object.
|
|
||||||
"""
|
|
||||||
def log_print(req_resp_dict, r_type):
|
|
||||||
msg = f"\n================== {r_type} details ==================\n"
|
|
||||||
for key, value in req_resp_dict[r_type].items():
|
|
||||||
msg += "{:<16} : {}\n".format(key, repr(value))
|
|
||||||
logger.debug(msg)
|
|
||||||
|
|
||||||
req_resp_dict = {
|
|
||||||
"request": {},
|
|
||||||
"response": {}
|
|
||||||
}
|
|
||||||
|
|
||||||
# record actual request info
|
|
||||||
req_resp_dict["request"]["url"] = resp_obj.request.url
|
|
||||||
req_resp_dict["request"]["method"] = resp_obj.request.method
|
|
||||||
req_resp_dict["request"]["headers"] = dict(resp_obj.request.headers)
|
|
||||||
|
|
||||||
request_body = resp_obj.request.body
|
|
||||||
if request_body:
|
|
||||||
request_content_type = lower_dict_keys(
|
|
||||||
req_resp_dict["request"]["headers"]
|
|
||||||
).get("content-type")
|
|
||||||
if request_content_type and "multipart/form-data" in request_content_type:
|
|
||||||
# upload file type
|
|
||||||
req_resp_dict["request"]["body"] = "upload file stream (OMITTED)"
|
|
||||||
else:
|
|
||||||
req_resp_dict["request"]["body"] = request_body
|
|
||||||
|
|
||||||
# log request details in debug mode
|
|
||||||
log_print(req_resp_dict, "request")
|
|
||||||
|
|
||||||
# record response info
|
|
||||||
req_resp_dict["response"]["ok"] = resp_obj.ok
|
|
||||||
req_resp_dict["response"]["url"] = resp_obj.url
|
|
||||||
req_resp_dict["response"]["status_code"] = resp_obj.status_code
|
|
||||||
req_resp_dict["response"]["reason"] = resp_obj.reason
|
|
||||||
req_resp_dict["response"]["cookies"] = resp_obj.cookies or {}
|
|
||||||
req_resp_dict["response"]["encoding"] = resp_obj.encoding
|
|
||||||
resp_headers = dict(resp_obj.headers)
|
|
||||||
req_resp_dict["response"]["headers"] = resp_headers
|
|
||||||
|
|
||||||
lower_resp_headers = lower_dict_keys(resp_headers)
|
|
||||||
content_type = lower_resp_headers.get("content-type", "")
|
|
||||||
req_resp_dict["response"]["content_type"] = content_type
|
|
||||||
|
|
||||||
if "image" in content_type:
|
|
||||||
# response is image type, record bytes content only
|
|
||||||
req_resp_dict["response"]["body"] = resp_obj.content
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
# try to record json data
|
|
||||||
if isinstance(resp_obj, response.ResponseObject):
|
|
||||||
req_resp_dict["response"]["body"] = resp_obj.json
|
|
||||||
else:
|
|
||||||
req_resp_dict["response"]["body"] = resp_obj.json()
|
|
||||||
except ValueError:
|
|
||||||
# only record at most 512 text charactors
|
|
||||||
resp_text = resp_obj.text
|
|
||||||
req_resp_dict["response"]["body"] = omit_long_data(resp_text)
|
|
||||||
|
|
||||||
# log response details in debug mode
|
|
||||||
log_print(req_resp_dict, "response")
|
|
||||||
|
|
||||||
return req_resp_dict
|
|
||||||
|
|
||||||
|
|
||||||
class ApiResponse(Response):
|
class ApiResponse(Response):
|
||||||
|
|
||||||
def raise_for_status(self):
|
def raise_for_status(self):
|
||||||
@@ -90,6 +22,73 @@ class ApiResponse(Response):
|
|||||||
Response.raise_for_status(self)
|
Response.raise_for_status(self)
|
||||||
|
|
||||||
|
|
||||||
|
def get_req_resp_record(resp_obj: Response) -> ReqRespData:
|
||||||
|
""" get request and response info from Response() object.
|
||||||
|
"""
|
||||||
|
def log_print(req_or_resp, r_type):
|
||||||
|
msg = f"\n================== {r_type} details ==================\n"
|
||||||
|
for key, value in req_or_resp.dict().items():
|
||||||
|
msg += "{:<16} : {}\n".format(key, repr(value))
|
||||||
|
logger.debug(msg)
|
||||||
|
|
||||||
|
# record actual request info
|
||||||
|
request_data = RequestData(
|
||||||
|
method=resp_obj.request.method,
|
||||||
|
url=resp_obj.request.url,
|
||||||
|
headers=dict(resp_obj.request.headers),
|
||||||
|
body=resp_obj.request.body
|
||||||
|
)
|
||||||
|
|
||||||
|
request_body = resp_obj.request.body
|
||||||
|
if request_body:
|
||||||
|
request_content_type = lower_dict_keys(
|
||||||
|
request_data.headers
|
||||||
|
).get("content-type")
|
||||||
|
if request_content_type and "multipart/form-data" in request_content_type:
|
||||||
|
# upload file type
|
||||||
|
request_data.body = "upload file stream (OMITTED)"
|
||||||
|
else:
|
||||||
|
request_data.body = request_body
|
||||||
|
|
||||||
|
# log request details in debug mode
|
||||||
|
log_print(request_data, "request")
|
||||||
|
|
||||||
|
# record response info
|
||||||
|
resp_headers = dict(resp_obj.headers)
|
||||||
|
lower_resp_headers = lower_dict_keys(resp_headers)
|
||||||
|
content_type = lower_resp_headers.get("content-type", "")
|
||||||
|
|
||||||
|
if "image" in content_type:
|
||||||
|
# response is image type, record bytes content only
|
||||||
|
response_body = resp_obj.content
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
# try to record json data
|
||||||
|
response_body = resp_obj.json()
|
||||||
|
except ValueError:
|
||||||
|
# only record at most 512 text charactors
|
||||||
|
resp_text = resp_obj.text
|
||||||
|
response_body = omit_long_data(resp_text)
|
||||||
|
|
||||||
|
response_data = ResponseData(
|
||||||
|
status_code=resp_obj.status_code,
|
||||||
|
cookies=resp_obj.cookies or {},
|
||||||
|
encoding=resp_obj.encoding,
|
||||||
|
headers=resp_headers,
|
||||||
|
content_type=content_type,
|
||||||
|
body=response_body
|
||||||
|
)
|
||||||
|
|
||||||
|
# log response details in debug mode
|
||||||
|
log_print(response_data, "response")
|
||||||
|
|
||||||
|
req_resp_data = ReqRespData(
|
||||||
|
request=request_data,
|
||||||
|
response=response_data
|
||||||
|
)
|
||||||
|
return req_resp_data
|
||||||
|
|
||||||
|
|
||||||
class HttpSession(requests.Session):
|
class HttpSession(requests.Session):
|
||||||
"""
|
"""
|
||||||
Class for performing HTTP requests and holding (session-) cookies between requests (in order
|
Class for performing HTTP requests and holding (session-) cookies between requests (in order
|
||||||
@@ -101,35 +100,15 @@ class HttpSession(requests.Session):
|
|||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(HttpSession, self).__init__()
|
super(HttpSession, self).__init__()
|
||||||
self.data = None
|
self.data = SessionData()
|
||||||
|
|
||||||
def init_session_data(self):
|
|
||||||
""" initialize session data, it will store detail data of request and response
|
|
||||||
"""
|
|
||||||
self.data = SessionData(
|
|
||||||
req_resp=[
|
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"url": "N/A",
|
|
||||||
"method": "N/A",
|
|
||||||
"headers": {}
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"status_code": "N/A",
|
|
||||||
"headers": {},
|
|
||||||
"encoding": None,
|
|
||||||
"content_type": ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def update_last_req_resp_record(self, resp_obj):
|
def update_last_req_resp_record(self, resp_obj):
|
||||||
"""
|
"""
|
||||||
update request and response info from Response() object.
|
update request and response info from Response() object.
|
||||||
"""
|
"""
|
||||||
self.data.req_resp.pop()
|
# TODO: fix
|
||||||
self.data.req_resp.append(get_req_resp_record(resp_obj))
|
self.data.req_resps.pop()
|
||||||
|
self.data.req_resps.append(get_req_resp_record(resp_obj))
|
||||||
|
|
||||||
def request(self, method, url, name=None, **kwargs):
|
def request(self, method, url, name=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
@@ -170,15 +149,10 @@ class HttpSession(requests.Session):
|
|||||||
:param cert: (optional)
|
:param cert: (optional)
|
||||||
if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
|
if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
|
||||||
"""
|
"""
|
||||||
self.init_session_data()
|
self.data = SessionData()
|
||||||
# record test name
|
|
||||||
self.data.name = name
|
|
||||||
|
|
||||||
# record original request info
|
# timeout default to 120 seconds
|
||||||
self.data.req_resp[0]["request"]["method"] = method
|
|
||||||
self.data.req_resp[0]["request"]["url"] = url
|
|
||||||
kwargs.setdefault("timeout", 120)
|
kwargs.setdefault("timeout", 120)
|
||||||
self.data.req_resp[0]["request"].update(kwargs)
|
|
||||||
|
|
||||||
start_timestamp = time.time()
|
start_timestamp = time.time()
|
||||||
response = self._send_request_safe_mode(method, url, **kwargs)
|
response = self._send_request_safe_mode(method, url, **kwargs)
|
||||||
@@ -198,7 +172,7 @@ class HttpSession(requests.Session):
|
|||||||
|
|
||||||
# record request and response histories, include 30X redirection
|
# record request and response histories, include 30X redirection
|
||||||
response_list = response.history + [response]
|
response_list = response.history + [response]
|
||||||
self.data.req_resp = [
|
self.data.req_resps = [
|
||||||
get_req_resp_record(resp_obj)
|
get_req_resp_record(resp_obj)
|
||||||
for resp_obj in response_list
|
for resp_obj in response_list
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -114,22 +114,6 @@ class ResponseObject(object):
|
|||||||
}
|
}
|
||||||
self.validation_results: Dict = {}
|
self.validation_results: Dict = {}
|
||||||
|
|
||||||
def __getattr__(self, key):
|
|
||||||
try:
|
|
||||||
if key == "json":
|
|
||||||
value = self.resp_obj.json()
|
|
||||||
elif key == "cookies":
|
|
||||||
value = self.resp_obj.cookies.get_dict()
|
|
||||||
else:
|
|
||||||
value = getattr(self.resp_obj, key)
|
|
||||||
|
|
||||||
self.__dict__[key] = value
|
|
||||||
return value
|
|
||||||
except AttributeError:
|
|
||||||
err_msg = f"ResponseObject does not have attribute: {key}"
|
|
||||||
logger.error(err_msg)
|
|
||||||
raise ParamsError(err_msg)
|
|
||||||
|
|
||||||
def extract(self, extractors: Dict[Text, Text]) -> Dict[Text, Any]:
|
def extract(self, extractors: Dict[Text, Text]) -> Dict[Text, Any]:
|
||||||
if not extractors:
|
if not extractors:
|
||||||
return {}
|
return {}
|
||||||
|
|||||||
+37
-15
@@ -7,7 +7,7 @@ from httprunner.client import HttpSession
|
|||||||
from httprunner.exceptions import ValidationFailure, ParamsError
|
from httprunner.exceptions import ValidationFailure, ParamsError
|
||||||
from httprunner.parser import build_url, parse_data, parse_variables_mapping
|
from httprunner.parser import build_url, parse_data, parse_variables_mapping
|
||||||
from httprunner.response import ResponseObject
|
from httprunner.response import ResponseObject
|
||||||
from httprunner.schema import TestsConfig, TestStep, VariablesMapping, TestCase, SessionData
|
from httprunner.schema import TestsConfig, TestStep, VariablesMapping, TestCase, StepData
|
||||||
|
|
||||||
|
|
||||||
class TestCaseRunner(object):
|
class TestCaseRunner(object):
|
||||||
@@ -15,9 +15,10 @@ class TestCaseRunner(object):
|
|||||||
config: TestsConfig = {}
|
config: TestsConfig = {}
|
||||||
teststeps: List[TestStep] = []
|
teststeps: List[TestStep] = []
|
||||||
session: HttpSession = None
|
session: HttpSession = None
|
||||||
step_datas: List[SessionData] = []
|
step_datas: List[StepData] = []
|
||||||
validation_results: Dict = {}
|
validation_results: Dict = {}
|
||||||
session_variables: Dict = {}
|
session_variables: Dict = {}
|
||||||
|
success: bool = True # indicate testcase execution result
|
||||||
|
|
||||||
def init(self, testcase: TestCase) -> "TestCaseRunner":
|
def init(self, testcase: TestCase) -> "TestCaseRunner":
|
||||||
self.config = testcase.config
|
self.config = testcase.config
|
||||||
@@ -34,6 +35,10 @@ class TestCaseRunner(object):
|
|||||||
|
|
||||||
def __run_step_request(self, step: TestStep):
|
def __run_step_request(self, step: TestStep):
|
||||||
"""run teststep: request"""
|
"""run teststep: request"""
|
||||||
|
step_data = StepData(
|
||||||
|
name=step.name
|
||||||
|
)
|
||||||
|
|
||||||
# parse
|
# parse
|
||||||
request_dict = step.request.dict()
|
request_dict = step.request.dict()
|
||||||
parsed_request_dict = parse_data(request_dict, step.variables, self.config.functions)
|
parsed_request_dict = parse_data(request_dict, step.variables, self.config.functions)
|
||||||
@@ -70,14 +75,15 @@ class TestCaseRunner(object):
|
|||||||
|
|
||||||
# log response
|
# log response
|
||||||
err_msg += "====== response details ======\n"
|
err_msg += "====== response details ======\n"
|
||||||
err_msg += f"status_code: {resp_obj.status_code}\n"
|
err_msg += f"status_code: {resp.status_code}\n"
|
||||||
err_msg += f"headers: {resp_obj.headers}\n"
|
err_msg += f"headers: {resp.headers}\n"
|
||||||
err_msg += f"body: {repr(resp_obj.text)}\n"
|
err_msg += f"body: {repr(resp.text)}\n"
|
||||||
logger.error(err_msg)
|
logger.error(err_msg)
|
||||||
|
|
||||||
# extract
|
# extract
|
||||||
extractors = step.extract
|
extractors = step.extract
|
||||||
extract_mapping = resp_obj.extract(extractors)
|
extract_mapping = resp_obj.extract(extractors)
|
||||||
|
step_data.export = extract_mapping
|
||||||
|
|
||||||
variables_mapping = step.variables
|
variables_mapping = step.variables
|
||||||
variables_mapping.update(extract_mapping)
|
variables_mapping.update(extract_mapping)
|
||||||
@@ -86,33 +92,49 @@ class TestCaseRunner(object):
|
|||||||
validators = step.validators
|
validators = step.validators
|
||||||
try:
|
try:
|
||||||
resp_obj.validate(validators, variables_mapping, self.config.functions)
|
resp_obj.validate(validators, variables_mapping, self.config.functions)
|
||||||
self.session.data.status = "passed"
|
self.session.data.success = True
|
||||||
except ValidationFailure:
|
except ValidationFailure:
|
||||||
self.session.data.status = "failed"
|
self.session.data.success = False
|
||||||
log_req_resp_details()
|
log_req_resp_details()
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
self.validation_results = resp_obj.validation_results
|
self.validation_results = resp_obj.validation_results
|
||||||
# save request & response meta data
|
# save request & response meta data
|
||||||
self.session.data.validators = self.validation_results
|
self.session.data.validators = self.validation_results
|
||||||
self.session.data.name = step.name
|
self.success &= self.session.data.success
|
||||||
self.step_datas.append(self.session.data)
|
|
||||||
|
|
||||||
return extract_mapping
|
step_data.success = self.session.data.success
|
||||||
|
step_data.data = self.session.data
|
||||||
|
return step_data
|
||||||
|
|
||||||
def __run_step_testcase(self, step):
|
def __run_step_testcase(self, step):
|
||||||
"""run teststep: referenced testcase"""
|
"""run teststep: referenced testcase"""
|
||||||
|
step_data = StepData(
|
||||||
|
name=step.name
|
||||||
|
)
|
||||||
step_variables = step.variables
|
step_variables = step.variables
|
||||||
testcase: TestCaseRunner = step.testcase
|
testcase: TestCaseRunner = step.testcase() # TODO: fix
|
||||||
res = testcase.with_variables(**step_variables).run()
|
case_result = testcase.with_variables(**step_variables).run()
|
||||||
return res.get_export_variables()
|
step_data.data = case_result.step_datas # list of step data
|
||||||
|
step_data.export = case_result.get_export_variables()
|
||||||
|
step_data.success = case_result.success
|
||||||
|
self.success &= case_result.success
|
||||||
|
|
||||||
|
return step_data
|
||||||
|
|
||||||
def __run_step(self, step: TestStep):
|
def __run_step(self, step: TestStep):
|
||||||
|
"""run teststep, teststep maybe a request or referenced testcase"""
|
||||||
logger.info(f"run step: {step.name}")
|
logger.info(f"run step: {step.name}")
|
||||||
|
|
||||||
if step.request:
|
if step.request:
|
||||||
return self.__run_step_request(step)
|
step_data = self.__run_step_request(step)
|
||||||
elif step.testcase:
|
elif step.testcase:
|
||||||
return self.__run_step_testcase(step)
|
step_data = self.__run_step_testcase(step)
|
||||||
|
else:
|
||||||
|
raise ParamsError(f"teststep is neither a request nor a referenced testcase: {step.dict()}")
|
||||||
|
|
||||||
|
self.step_datas.append(step_data)
|
||||||
|
return step_data.export
|
||||||
|
|
||||||
def test_start(self):
|
def test_start(self):
|
||||||
"""main entrance"""
|
"""main entrance"""
|
||||||
|
|||||||
+43
-10
@@ -43,6 +43,7 @@ class TestsConfig(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class Request(BaseModel):
|
class Request(BaseModel):
|
||||||
|
"""requests.Request model"""
|
||||||
method: MethodEnum = MethodEnum.GET
|
method: MethodEnum = MethodEnum.GET
|
||||||
url: Url
|
url: Url
|
||||||
params: Dict[Text, Text] = {}
|
params: Dict[Text, Text] = {}
|
||||||
@@ -84,9 +85,9 @@ class TestsMapping(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class TestCaseTime(BaseModel):
|
class TestCaseTime(BaseModel):
|
||||||
start_at: float
|
start_at: float = 0
|
||||||
start_at_iso_format: Text
|
start_at_iso_format: Text = ""
|
||||||
duration: float
|
duration: float = 0
|
||||||
|
|
||||||
|
|
||||||
class TestCaseInOut(BaseModel):
|
class TestCaseInOut(BaseModel):
|
||||||
@@ -100,14 +101,46 @@ class RequestStat(BaseModel):
|
|||||||
elapsed_ms: float = 0
|
elapsed_ms: float = 0
|
||||||
|
|
||||||
|
|
||||||
|
class RequestData(BaseModel):
|
||||||
|
method: MethodEnum = MethodEnum.GET
|
||||||
|
url: Url
|
||||||
|
headers: Headers = {}
|
||||||
|
# TODO: add cookies
|
||||||
|
body: Union[Text, Dict] = {}
|
||||||
|
|
||||||
|
|
||||||
|
class ResponseData(BaseModel):
|
||||||
|
status_code: int
|
||||||
|
cookies: Dict
|
||||||
|
encoding: Text
|
||||||
|
headers: Dict
|
||||||
|
content_type: Text
|
||||||
|
body: Union[Text, bytes, Dict]
|
||||||
|
|
||||||
|
|
||||||
|
class ReqRespData(BaseModel):
|
||||||
|
request: RequestData
|
||||||
|
response: ResponseData
|
||||||
|
|
||||||
|
|
||||||
class SessionData(BaseModel):
|
class SessionData(BaseModel):
|
||||||
status: Text = ""
|
"""request session data, including request, response, validators and stat data"""
|
||||||
name: Text = ""
|
success: bool = False
|
||||||
req_resp: List[Dict] = []
|
# 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()
|
stat: RequestStat = RequestStat()
|
||||||
validators: Dict = {}
|
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[SessionData]] = None
|
||||||
|
export: Dict = {}
|
||||||
|
|
||||||
|
|
||||||
class TestCaseSummary(BaseModel):
|
class TestCaseSummary(BaseModel):
|
||||||
name: Text = ""
|
name: Text = ""
|
||||||
success: bool
|
success: bool
|
||||||
@@ -116,7 +149,7 @@ class TestCaseSummary(BaseModel):
|
|||||||
time: TestCaseTime
|
time: TestCaseTime
|
||||||
in_out: TestCaseInOut = {}
|
in_out: TestCaseInOut = {}
|
||||||
log: Text = ""
|
log: Text = ""
|
||||||
step_datas: List[SessionData] = []
|
step_datas: List[StepData] = []
|
||||||
|
|
||||||
|
|
||||||
class PlatformInfo(BaseModel):
|
class PlatformInfo(BaseModel):
|
||||||
@@ -132,8 +165,8 @@ class Stat(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class TestSuiteSummary(BaseModel):
|
class TestSuiteSummary(BaseModel):
|
||||||
success: bool
|
success: bool = False
|
||||||
stat: Stat
|
stat: Stat = Stat()
|
||||||
time: TestCaseTime
|
time: TestCaseTime = TestCaseTime()
|
||||||
platform: PlatformInfo
|
platform: PlatformInfo
|
||||||
testcases: List[TestCaseSummary]
|
testcases: List[TestCaseSummary]
|
||||||
|
|||||||
Reference in New Issue
Block a user