mirror of
https://github.com/httprunner/httprunner.git
synced 2026-09-04 23:16:57 +08:00
feat: extract session variable from referenced testcase step
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
**Added**
|
**Added**
|
||||||
|
|
||||||
- feat: add sentry sdk
|
- feat: add sentry sdk
|
||||||
|
- feat: extract session variable from referenced testcase step
|
||||||
|
|
||||||
**Fixed**
|
**Fixed**
|
||||||
|
|
||||||
|
|||||||
+1
@@ -10,6 +10,7 @@ class TestCaseRequestWithFunctions(HttpRunner):
|
|||||||
.variables(**{"foo1": "session_bar1", "var1": "testsuite_val1"})
|
.variables(**{"foo1": "session_bar1", "var1": "testsuite_val1"})
|
||||||
.base_url("https://postman-echo.com")
|
.base_url("https://postman-echo.com")
|
||||||
.verify(False)
|
.verify(False)
|
||||||
|
.export(*["session_foo2"])
|
||||||
)
|
)
|
||||||
|
|
||||||
teststeps = [
|
teststeps = [
|
||||||
|
|||||||
+17
@@ -26,6 +26,23 @@ class TestCaseRequestWithTestcaseReference(HttpRunner):
|
|||||||
RunTestCase("request with functions")
|
RunTestCase("request with functions")
|
||||||
.with_variables(**{"foo1": "override_bar1"})
|
.with_variables(**{"foo1": "override_bar1"})
|
||||||
.call(RequestWithFunctions)
|
.call(RequestWithFunctions)
|
||||||
|
.extract(*["session_foo2"])
|
||||||
|
),
|
||||||
|
Step(
|
||||||
|
RunRequest("post form data")
|
||||||
|
.with_variables(**{"foo1": "bar1"})
|
||||||
|
.post("/post")
|
||||||
|
.with_headers(
|
||||||
|
**{
|
||||||
|
"User-Agent": "HttpRunner/${get_httprunner_version()}",
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.with_data("foo1=$foo1&foo2=$session_foo2")
|
||||||
|
.validate()
|
||||||
|
.assert_equal("status_code", 200)
|
||||||
|
.assert_equal("body.form.foo1", "session_bar1")
|
||||||
|
.assert_equal("body.form.foo2", "session_bar2")
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ config:
|
|||||||
foo1: session_bar1
|
foo1: session_bar1
|
||||||
base_url: "https://postman-echo.com"
|
base_url: "https://postman-echo.com"
|
||||||
verify: False
|
verify: False
|
||||||
|
export: ["session_foo2"]
|
||||||
|
|
||||||
teststeps:
|
teststeps:
|
||||||
-
|
-
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ class TestCaseRequestWithFunctions(HttpRunner):
|
|||||||
.variables(**{"foo1": "session_bar1"})
|
.variables(**{"foo1": "session_bar1"})
|
||||||
.base_url("https://postman-echo.com")
|
.base_url("https://postman-echo.com")
|
||||||
.verify(False)
|
.verify(False)
|
||||||
|
.export(*["session_foo2"])
|
||||||
)
|
)
|
||||||
|
|
||||||
teststeps = [
|
teststeps = [
|
||||||
|
|||||||
@@ -11,3 +11,20 @@ teststeps:
|
|||||||
variables:
|
variables:
|
||||||
foo1: override_bar1
|
foo1: override_bar1
|
||||||
testcase: request_methods/request_with_functions.yml
|
testcase: request_methods/request_with_functions.yml
|
||||||
|
extract:
|
||||||
|
- session_foo2
|
||||||
|
-
|
||||||
|
name: post form data
|
||||||
|
variables:
|
||||||
|
foo1: bar1
|
||||||
|
request:
|
||||||
|
method: POST
|
||||||
|
url: /post
|
||||||
|
headers:
|
||||||
|
User-Agent: HttpRunner/${get_httprunner_version()}
|
||||||
|
Content-Type: "application/x-www-form-urlencoded"
|
||||||
|
data: "foo1=$foo1&foo2=$session_foo2"
|
||||||
|
validate:
|
||||||
|
- eq: ["status_code", 200]
|
||||||
|
- eq: ["body.form.foo1", "session_bar1"]
|
||||||
|
- eq: ["body.form.foo2", "session_bar2"]
|
||||||
|
|||||||
@@ -26,6 +26,23 @@ class TestCaseRequestWithTestcaseReference(HttpRunner):
|
|||||||
RunTestCase("request with functions")
|
RunTestCase("request with functions")
|
||||||
.with_variables(**{"foo1": "override_bar1"})
|
.with_variables(**{"foo1": "override_bar1"})
|
||||||
.call(RequestWithFunctions)
|
.call(RequestWithFunctions)
|
||||||
|
.extract(*["session_foo2"])
|
||||||
|
),
|
||||||
|
Step(
|
||||||
|
RunRequest("post form data")
|
||||||
|
.with_variables(**{"foo1": "bar1"})
|
||||||
|
.post("/post")
|
||||||
|
.with_headers(
|
||||||
|
**{
|
||||||
|
"User-Agent": "HttpRunner/${get_httprunner_version()}",
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.with_data("foo1=$foo1&foo2=$session_foo2")
|
||||||
|
.validate()
|
||||||
|
.assert_equal("status_code", 200)
|
||||||
|
.assert_equal("body.form.foo1", "session_bar1")
|
||||||
|
.assert_equal("body.form.foo2", "session_bar2")
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,10 @@ def ensure_step_attachment(step: Dict) -> Dict:
|
|||||||
test_dict["teardown_hooks"] = step["teardown_hooks"]
|
test_dict["teardown_hooks"] = step["teardown_hooks"]
|
||||||
|
|
||||||
if "extract" in step:
|
if "extract" in step:
|
||||||
test_dict["extract"] = convert_extractors(step["extract"])
|
if step.get("request"):
|
||||||
|
test_dict["extract"] = convert_extractors(step["extract"])
|
||||||
|
elif step.get("testcase"):
|
||||||
|
test_dict["extract"] = step["extract"]
|
||||||
|
|
||||||
if "validate" in step:
|
if "validate" in step:
|
||||||
test_dict["validate"] = convert_validators(step["validate"])
|
test_dict["validate"] = convert_validators(step["validate"])
|
||||||
@@ -164,6 +167,8 @@ def ensure_testcase_v3(test_content: Dict) -> Dict:
|
|||||||
for step in test_content["teststeps"]:
|
for step in test_content["teststeps"]:
|
||||||
teststep = {}
|
teststep = {}
|
||||||
|
|
||||||
|
teststep.update(ensure_step_attachment(step))
|
||||||
|
|
||||||
if "request" in step:
|
if "request" in step:
|
||||||
teststep["request"] = step.pop("request")
|
teststep["request"] = step.pop("request")
|
||||||
elif "api" in step:
|
elif "api" in step:
|
||||||
@@ -171,7 +176,6 @@ def ensure_testcase_v3(test_content: Dict) -> Dict:
|
|||||||
elif "testcase" in step:
|
elif "testcase" in step:
|
||||||
teststep["testcase"] = step.pop("testcase")
|
teststep["testcase"] = step.pop("testcase")
|
||||||
|
|
||||||
teststep.update(ensure_step_attachment(step))
|
|
||||||
teststep = sort_step_by_custom_order(teststep)
|
teststep = sort_step_by_custom_order(teststep)
|
||||||
v3_content["teststeps"].append(teststep)
|
v3_content["teststeps"].append(teststep)
|
||||||
|
|
||||||
|
|||||||
+16
-6
@@ -149,6 +149,9 @@ def make_config_chain_style(config: Dict) -> Text:
|
|||||||
if "verify" in config:
|
if "verify" in config:
|
||||||
config_chain_style += f'.verify({config["verify"]})'
|
config_chain_style += f'.verify({config["verify"]})'
|
||||||
|
|
||||||
|
if "export" in config:
|
||||||
|
config_chain_style += f'.export(*{config["export"]})'
|
||||||
|
|
||||||
return config_chain_style
|
return config_chain_style
|
||||||
|
|
||||||
|
|
||||||
@@ -204,7 +207,7 @@ def make_teststep_chain_style(teststep: Dict) -> Text:
|
|||||||
elif teststep.get("testcase"):
|
elif teststep.get("testcase"):
|
||||||
step_info = f'RunTestCase("{teststep["name"]}")'
|
step_info = f'RunTestCase("{teststep["name"]}")'
|
||||||
else:
|
else:
|
||||||
raise exceptions.TestCaseFormatError
|
raise exceptions.TestCaseFormatError(f"Invalid teststep: {teststep}")
|
||||||
|
|
||||||
if "variables" in teststep:
|
if "variables" in teststep:
|
||||||
variables = teststep["variables"]
|
variables = teststep["variables"]
|
||||||
@@ -217,11 +220,18 @@ def make_teststep_chain_style(teststep: Dict) -> Text:
|
|||||||
call_ref_testcase = f".call({testcase})"
|
call_ref_testcase = f".call({testcase})"
|
||||||
step_info += call_ref_testcase
|
step_info += call_ref_testcase
|
||||||
|
|
||||||
if "extract" in teststep:
|
extract_info = teststep.get("extract")
|
||||||
step_info += ".extract()"
|
if extract_info:
|
||||||
|
if isinstance(extract_info, Dict):
|
||||||
for extract_name, extract_path in teststep["extract"].items():
|
# request step
|
||||||
step_info += f'.with_jmespath("{extract_path}", "{extract_name}")'
|
step_info += ".extract()"
|
||||||
|
for extract_name, extract_path in extract_info.items():
|
||||||
|
step_info += f'.with_jmespath("{extract_path}", "{extract_name}")'
|
||||||
|
elif isinstance(extract_info, List):
|
||||||
|
# reference testcase step
|
||||||
|
step_info += f".extract(*{extract_info})"
|
||||||
|
else:
|
||||||
|
raise exceptions.TestCaseFormatError(f"Invalid extract: {extract_info}")
|
||||||
|
|
||||||
if "validate" in teststep:
|
if "validate" in teststep:
|
||||||
step_info += ".validate()"
|
step_info += ".validate()"
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class TStep(BaseModel):
|
|||||||
variables: VariablesMapping = {}
|
variables: VariablesMapping = {}
|
||||||
setup_hooks: Hook = []
|
setup_hooks: Hook = []
|
||||||
teardown_hooks: Hook = []
|
teardown_hooks: Hook = []
|
||||||
extract: Dict[Text, Text] = {}
|
extract: Union[Dict[Text, Text], List[Text]] = {}
|
||||||
validators: Validators = Field([], alias="validate")
|
validators: Validators = Field([], alias="validate")
|
||||||
validate_script: List[Text] = []
|
validate_script: List[Text] = []
|
||||||
|
|
||||||
|
|||||||
+32
-5
@@ -16,6 +16,7 @@ class Config(object):
|
|||||||
self.__variables = {}
|
self.__variables = {}
|
||||||
self.__base_url = ""
|
self.__base_url = ""
|
||||||
self.__verify = False
|
self.__verify = False
|
||||||
|
self.__export = []
|
||||||
|
|
||||||
caller_frame = inspect.stack()[1]
|
caller_frame = inspect.stack()[1]
|
||||||
self.__path = caller_frame.filename
|
self.__path = caller_frame.filename
|
||||||
@@ -40,12 +41,17 @@ class Config(object):
|
|||||||
self.__verify = verify
|
self.__verify = verify
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def export(self, *export_var_name: Text) -> "Config":
|
||||||
|
self.__export.extend(export_var_name)
|
||||||
|
return self
|
||||||
|
|
||||||
def perform(self) -> TConfig:
|
def perform(self) -> TConfig:
|
||||||
return TConfig(
|
return TConfig(
|
||||||
name=self.__name,
|
name=self.__name,
|
||||||
base_url=self.__base_url,
|
base_url=self.__base_url,
|
||||||
verify=self.__verify,
|
verify=self.__verify,
|
||||||
variables=self.__variables,
|
variables=self.__variables,
|
||||||
|
export=list(set(self.__export)),
|
||||||
path=self.__path,
|
path=self.__path,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,7 +60,9 @@ class StepRequestValidation(object):
|
|||||||
def __init__(self, step: TStep):
|
def __init__(self, step: TStep):
|
||||||
self.__t_step = step
|
self.__t_step = step
|
||||||
|
|
||||||
def assert_equal(self, jmes_path: Text, expected_value: Any) -> "StepRequestValidation":
|
def assert_equal(
|
||||||
|
self, jmes_path: Text, expected_value: Any
|
||||||
|
) -> "StepRequestValidation":
|
||||||
self.__t_step.validators.append({"equal": [jmes_path, expected_value]})
|
self.__t_step.validators.append({"equal": [jmes_path, expected_value]})
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -152,7 +160,9 @@ class StepRequestValidation(object):
|
|||||||
self.__t_step.validators.append({"regex_match": [jmes_path, expected_value]})
|
self.__t_step.validators.append({"regex_match": [jmes_path, expected_value]})
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def assert_contains(self, jmes_path: Text, expected_value: Any) -> "StepRequestValidation":
|
def assert_contains(
|
||||||
|
self, jmes_path: Text, expected_value: Any
|
||||||
|
) -> "StepRequestValidation":
|
||||||
self.__t_step.validators.append({"contains": [jmes_path, expected_value]})
|
self.__t_step.validators.append({"contains": [jmes_path, expected_value]})
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@@ -285,6 +295,19 @@ class RunRequest(object):
|
|||||||
return RequestWithOptionalArgs(self.__t_step)
|
return RequestWithOptionalArgs(self.__t_step)
|
||||||
|
|
||||||
|
|
||||||
|
class StepRefCase(object):
|
||||||
|
def __init__(self, step: TStep):
|
||||||
|
self.__t_step = step
|
||||||
|
self.__t_step.extract = []
|
||||||
|
|
||||||
|
def extract(self, *var_name: Text) -> "StepRefCase":
|
||||||
|
self.__t_step.extract.extend(var_name)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def perform(self) -> TStep:
|
||||||
|
return self.__t_step
|
||||||
|
|
||||||
|
|
||||||
class RunTestCase(object):
|
class RunTestCase(object):
|
||||||
def __init__(self, name: Text):
|
def __init__(self, name: Text):
|
||||||
self.__t_step = TStep(name=name)
|
self.__t_step = TStep(name=name)
|
||||||
@@ -293,9 +316,9 @@ class RunTestCase(object):
|
|||||||
self.__t_step.variables.update(variables)
|
self.__t_step.variables.update(variables)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def call(self, testcase: Callable):
|
def call(self, testcase: Callable) -> StepRefCase:
|
||||||
self.__t_step.testcase = testcase
|
self.__t_step.testcase = testcase
|
||||||
return self
|
return StepRefCase(self.__t_step)
|
||||||
|
|
||||||
def perform(self) -> TStep:
|
def perform(self) -> TStep:
|
||||||
return self.__t_step
|
return self.__t_step
|
||||||
@@ -305,7 +328,11 @@ class Step(object):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
step: Union[
|
step: Union[
|
||||||
StepRequestValidation, StepRequestExtraction, RequestWithOptionalArgs, RunTestCase
|
StepRequestValidation,
|
||||||
|
StepRequestExtraction,
|
||||||
|
RequestWithOptionalArgs,
|
||||||
|
RunTestCase,
|
||||||
|
StepRefCase,
|
||||||
],
|
],
|
||||||
):
|
):
|
||||||
self.__t_step = step.perform()
|
self.__t_step = step.perform()
|
||||||
|
|||||||
@@ -25,4 +25,4 @@ class TestHttpRunner(unittest.TestCase):
|
|||||||
self.assertTrue(result.success)
|
self.assertTrue(result.success)
|
||||||
self.assertEqual(result.name, "request methods testcase: reference testcase")
|
self.assertEqual(result.name, "request methods testcase: reference testcase")
|
||||||
self.assertEqual(result.step_datas[0].name, "request with functions")
|
self.assertEqual(result.step_datas[0].name, "request with functions")
|
||||||
self.assertEqual(len(result.step_datas), 1)
|
self.assertEqual(len(result.step_datas), 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user