From adf0967888ed9581a2cd137952e964513c409a5e Mon Sep 17 00:00:00 2001 From: debugtalk Date: Fri, 5 Jun 2020 11:31:51 +0800 Subject: [PATCH] refactor: use step export to export session variables from referenced testcase --- .../request_with_testcase_reference.yml | 2 +- .../request_with_testcase_reference_test.py | 2 +- httprunner/compat.py | 12 ++++----- httprunner/make.py | 23 ++++++++--------- httprunner/models.py | 5 +++- httprunner/runner.py | 25 +++++++++++-------- httprunner/testcase.py | 5 ++-- 7 files changed, 39 insertions(+), 35 deletions(-) diff --git a/examples/postman_echo/request_methods/request_with_testcase_reference.yml b/examples/postman_echo/request_methods/request_with_testcase_reference.yml index 85138047..37871f2c 100644 --- a/examples/postman_echo/request_methods/request_with_testcase_reference.yml +++ b/examples/postman_echo/request_methods/request_with_testcase_reference.yml @@ -11,7 +11,7 @@ teststeps: variables: foo1: override_bar1 testcase: request_methods/request_with_functions.yml - extract: + export: - session_foo2 - name: post form data diff --git a/examples/postman_echo/request_methods/request_with_testcase_reference_test.py b/examples/postman_echo/request_methods/request_with_testcase_reference_test.py index 837dff4d..75c211ff 100644 --- a/examples/postman_echo/request_methods/request_with_testcase_reference_test.py +++ b/examples/postman_echo/request_methods/request_with_testcase_reference_test.py @@ -26,7 +26,7 @@ class TestCaseRequestWithTestcaseReference(HttpRunner): RunTestCase("request with functions") .with_variables(**{"foo1": "override_bar1"}) .call(RequestWithFunctions) - .extract(*["session_foo2"]) + .export(*["session_foo2"]) ), Step( RunRequest("post form data") diff --git a/httprunner/compat.py b/httprunner/compat.py index 54addff2..8f919300 100644 --- a/httprunner/compat.py +++ b/httprunner/compat.py @@ -133,10 +133,10 @@ def ensure_step_attachment(step: Dict) -> Dict: test_dict["teardown_hooks"] = step["teardown_hooks"] if "extract" in step: - if step.get("request"): - test_dict["extract"] = convert_extractors(step["extract"]) - elif step.get("testcase"): - test_dict["extract"] = step["extract"] + test_dict["extract"] = convert_extractors(step["extract"]) + + if "export" in step: + test_dict["export"] = step["export"] if "validate" in step: test_dict["validate"] = convert_validators(step["validate"]) @@ -167,8 +167,6 @@ def ensure_testcase_v3(test_content: Dict) -> Dict: for step in test_content["teststeps"]: teststep = {} - teststep.update(ensure_step_attachment(step)) - if "request" in step: teststep["request"] = step.pop("request") elif "api" in step: @@ -176,6 +174,8 @@ def ensure_testcase_v3(test_content: Dict) -> Dict: elif "testcase" in step: teststep["testcase"] = step.pop("testcase") + teststep.update(ensure_step_attachment(step)) + teststep = sort_step_by_custom_order(teststep) v3_content["teststeps"].append(teststep) diff --git a/httprunner/make.py b/httprunner/make.py index 66fd9a1b..5a1dcfc0 100644 --- a/httprunner/make.py +++ b/httprunner/make.py @@ -220,18 +220,16 @@ def make_teststep_chain_style(teststep: Dict) -> Text: call_ref_testcase = f".call({testcase})" step_info += call_ref_testcase - extract_info = teststep.get("extract") - if extract_info: - if isinstance(extract_info, Dict): - # request step - 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 "extract" in teststep: + # request step + step_info += ".extract()" + for extract_name, extract_path in teststep["extract"].items(): + step_info += f'.with_jmespath("{extract_path}", "{extract_name}")' + + if "export" in teststep: + # reference testcase step + export: List[Text] = teststep["export"] + step_info += f".export(*{export})" if "validate" in teststep: step_info += ".validate()" @@ -455,6 +453,7 @@ def main_make(tests_paths: List[Text]) -> List[Text]: pytest_files_set.update(make_files_cache_set) pytest_files_list = list(pytest_files_set) + # TODO: format referenced testcase format_pytest_with_black(*pytest_files_list) return pytest_files_list diff --git a/httprunner/models.py b/httprunner/models.py index be60bf41..8389a886 100644 --- a/httprunner/models.py +++ b/httprunner/models.py @@ -66,7 +66,10 @@ class TStep(BaseModel): variables: VariablesMapping = {} setup_hooks: Hook = [] teardown_hooks: Hook = [] - extract: Union[Dict[Text, Text], List[Text]] = {} + # used to extract request's response field + extract: Dict[Text, Text] = {} + # used to export session variables from referenced testcase + export: List[Text] = [] validators: Validators = Field([], alias="validate") validate_script: List[Text] = [] diff --git a/httprunner/runner.py b/httprunner/runner.py index 4a3e77be..af280a9c 100644 --- a/httprunner/runner.py +++ b/httprunner/runner.py @@ -43,10 +43,10 @@ class HttpRunner(object): __teststeps: List[TStep] __project_meta: ProjectMeta = None __case_id: Text = "" + __export: List[Text] = [] __step_datas: List[StepData] = None __session: HttpSession = None __session_variables: VariablesMapping = {} - __export_variables: VariablesMapping = {} # time __start_at: float = 0 __duration: float = 0 @@ -82,6 +82,10 @@ class HttpRunner(object): self.__session_variables = variables return self + def with_export(self, export: List[Text]) -> "HttpRunner": + self.__export = export + return self + def __run_step_request(self, step: TStep) -> StepData: """run teststep: request""" step_data = StepData(name=step.name) @@ -166,6 +170,7 @@ class HttpRunner(object): """run teststep: referenced testcase""" step_data = StepData(name=step.name) step_variables = step.variables + step_export = step.export if hasattr(step.testcase, "config") and hasattr(step.testcase, "teststeps"): testcase_cls = step.testcase @@ -174,6 +179,7 @@ class HttpRunner(object): .with_session(self.__session) .with_case_id(self.__case_id) .with_variables(step_variables) + .with_export(step_export) .run() ) @@ -188,6 +194,7 @@ class HttpRunner(object): .with_session(self.__session) .with_case_id(self.__case_id) .with_variables(step_variables) + .with_export(step_export) .run_path(ref_testcase_path) ) @@ -201,6 +208,9 @@ class HttpRunner(object): step_data.success = case_result.success self.success &= case_result.success + if step_data.export: + logger.info(f"export variables: {step_data.export}") + return step_data def __run_step(self, step: TStep) -> Dict: @@ -252,7 +262,6 @@ class HttpRunner(object): self.__step_datas: List[StepData] = [] self.__session = self.__session or HttpSession() self.__session_variables = {} - self.__export_variables = {} # run teststeps for step in self.__teststeps: @@ -274,11 +283,6 @@ class HttpRunner(object): self.__session_variables.update(extract_mapping) self.__duration = time.time() - self.__start_at - - self.__export_variables = self.get_export_variables() - if self.__export_variables: - logger.info(f"export variables: {self.__export_variables}") - return self def run_path(self, path: Text) -> "HttpRunner": @@ -303,11 +307,10 @@ class HttpRunner(object): return self.__step_datas def get_export_variables(self) -> Dict: - if self.__export_variables: - return self.__export_variables - + # override testcase export vars with step export + export_var_names = self.__export or self.__config.export export_vars_mapping = {} - for var_name in self.__config.export: + for var_name in export_var_names: if var_name not in self.__session_variables: raise ParamsError( f"failed to export variable {var_name} from session variables {self.__session_variables}" diff --git a/httprunner/testcase.py b/httprunner/testcase.py index 3d9f8c3a..30016adc 100644 --- a/httprunner/testcase.py +++ b/httprunner/testcase.py @@ -298,10 +298,9 @@ class RunRequest(object): 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) + def export(self, *var_name: Text) -> "StepRefCase": + self.__t_step.export.extend(var_name) return self def perform(self) -> TStep: