diff --git a/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py b/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py index acb70cd0..da34ceca 100644 --- a/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py +++ b/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_functions_test.py @@ -7,7 +7,7 @@ from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseRequestWithFunctions(HttpRunner): config = ( Config("request with functions") - .variables(**{"foo1": "session_bar1", "var1": "testsuite_val1"}) + .variables(**{"var1": "testsuite_val1", "foo1": "session_bar1"}) .base_url("https://postman-echo.com") .verify(False) .export(*["session_foo2"]) diff --git a/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py b/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py index 294df37f..af45b5ba 100644 --- a/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py +++ b/examples/postman_echo/request_methods/demo_testsuite_yml/request_with_testcase_reference_test.py @@ -16,7 +16,7 @@ from examples.postman_echo.request_methods.request_with_functions_test import ( class TestCaseRequestWithTestcaseReference(HttpRunner): config = ( Config("request with referenced testcase") - .variables(**{"foo1": "session_bar1", "var2": "testsuite_val2"}) + .variables(**{"var2": "testsuite_val2", "foo1": "session_bar1"}) .base_url("https://postman-echo.com") .verify(False) ) diff --git a/httprunner/compat.py b/httprunner/compat.py index e683eaf5..35b996f9 100644 --- a/httprunner/compat.py +++ b/httprunner/compat.py @@ -3,15 +3,49 @@ This module handles compatibility issues between testcase format v2 and v3. """ import os import sys -from typing import List, Dict, Text, Union +from typing import List, Dict, Text, Union, Any from loguru import logger from httprunner import exceptions from httprunner.loader import load_project_meta +from httprunner.parser import parse_data from httprunner.utils import sort_dict_by_custom_order, ensure_file_path_valid +def convert_variables( + raw_variables: Union[Dict, List, Text], test_path: Text +) -> Dict[Text, Any]: + + if isinstance(raw_variables, Dict): + return raw_variables + + if isinstance(raw_variables, List): + # [{"var1": 1}, {"var2": 2}] + variables: Dict[Text, Any] = {} + for var_item in raw_variables: + if not isinstance(var_item, Dict) or len(var_item) != 1: + raise exceptions.TestCaseFormatError( + f"Invalid variables format: {raw_variables}" + ) + + variables.update(var_item) + + return variables + + elif isinstance(raw_variables, Text): + # get variables by function, e.g. ${get_variables()} + project_meta = load_project_meta(test_path) + variables = parse_data(raw_variables, {}, project_meta.functions) + + return variables + + else: + raise exceptions.TestCaseFormatError( + f"Invalid variables format: {raw_variables}" + ) + + def convert_jmespath(raw: Text) -> Text: # content.xx/json.xx => body.xx if raw.startswith("content"): diff --git a/httprunner/make.py b/httprunner/make.py index 670901aa..8dcdbb5c 100644 --- a/httprunner/make.py +++ b/httprunner/make.py @@ -9,7 +9,11 @@ from loguru import logger from sentry_sdk import capture_exception from httprunner import exceptions, __version__ -from httprunner.compat import ensure_testcase_v3_api, ensure_testcase_v3 +from httprunner.compat import ( + ensure_testcase_v3_api, + ensure_testcase_v3, + convert_variables, +) from httprunner.loader import ( load_folder_files, load_test_file, @@ -285,15 +289,9 @@ def make_testcase(testcase: Dict, dir_path: Text = None) -> Text: config = testcase["config"] config["path"] = __ensure_cwd_relative(testcase_python_path) - - # parse config variables - config.setdefault("variables", {}) - if isinstance(config["variables"], Text): - # get variables by function, e.g. ${get_variables()} - project_meta = load_project_meta(testcase_abs_path) - config["variables"] = parse_data( - config["variables"], {}, project_meta.functions - ) + config["variables"] = convert_variables( + config.get("variables", {}), testcase_abs_path + ) # prepare reference testcase imports_list = [] @@ -357,14 +355,9 @@ def make_testsuite(testsuite: Dict) -> NoReturn: testsuite_config = testsuite["config"] testsuite_path = testsuite_config["path"] - - testsuite_variables = testsuite_config.get("variables", {}) - if isinstance(testsuite_variables, Text): - # get variables by function, e.g. ${get_variables()} - project_meta = load_project_meta(testsuite_path) - testsuite_variables = parse_data( - testsuite_variables, {}, project_meta.functions - ) + testsuite_variables = convert_variables( + testsuite_config.get("variables", {}), testsuite_path + ) logger.info(f"start to make testsuite: {testsuite_path}") @@ -392,9 +385,11 @@ def make_testsuite(testsuite: Dict) -> NoReturn: if "verify" in testsuite_config: testcase_dict["config"]["verify"] = testsuite_config["verify"] # override variables - testcase_dict["config"].setdefault("variables", {}) - testcase_dict["config"]["variables"].update(testcase.get("variables", {})) - testcase_dict["config"]["variables"].update(testsuite_variables) + testcase_variables = convert_variables( + testcase.get("variables", {}), testcase_path + ) + testcase_variables.update(testsuite_variables) + testcase_dict["config"]["variables"] = testcase_variables # make testcase testcase_pytest_path = make_testcase(testcase_dict, testsuite_dir) diff --git a/tests/compat_test.py b/tests/compat_test.py index 89707db7..5e80e6d6 100644 --- a/tests/compat_test.py +++ b/tests/compat_test.py @@ -1,10 +1,34 @@ import os import unittest -from httprunner import compat +from httprunner import compat, exceptions +from httprunner.compat import convert_variables class TestCompat(unittest.TestCase): + def test_convert_variables(self): + raw_variables = [{"var1": 1}, {"var2": "val2"}] + self.assertEqual( + convert_variables(raw_variables, "tests/data/a-b.c/1.yml"), + {"var1": 1, "var2": "val2"}, + ) + raw_variables = {"var1": 1, "var2": "val2"} + self.assertEqual( + convert_variables(raw_variables, "tests/data/a-b.c/1.yml"), + {"var1": 1, "var2": "val2"}, + ) + raw_variables = "${get_variables()}" + self.assertEqual( + convert_variables(raw_variables, "tests/data/a-b.c/1.yml"), + {"foo1": "session_bar1"}, + ) + + with self.assertRaises(exceptions.TestCaseFormatError): + raw_variables = [{"var1": 1}, {"var2": "val2", "var3": 3}] + convert_variables(raw_variables, "tests/data/a-b.c/1.yml") + with self.assertRaises(exceptions.TestCaseFormatError): + convert_variables(None, "tests/data/a-b.c/1.yml") + def test_convert_jmespath(self): self.assertEqual(compat.convert_jmespath("content.abc"), "body.abc")