From 4dde8dd2b2a2ee834839450a91863cfdb4ef2a5c Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 6 Jul 2020 15:23:35 +0800 Subject: [PATCH] refactor: parameters --- examples/postman_echo/debugtalk.py | 5 ++ .../request_with_functions_test.py | 3 +- .../request_with_testcase_reference_test.py | 3 +- .../request_methods/hardcode_test.py | 3 +- .../request_with_functions_test.py | 3 +- .../request_with_parameters_test.py | 27 +++--- .../request_with_testcase_reference_test.py | 3 +- .../request_with_variables_test.py | 3 +- .../validate_with_functions_test.py | 3 +- .../validate_with_variables_test.py | 3 +- httprunner/__init__.py | 2 + httprunner/make.py | 43 ++++------ httprunner/parser.py | 82 ++++++++++--------- httprunner/utils.py | 39 +-------- tests/make_test.py | 24 +----- tests/parser_test.py | 56 +++++++------ tests/utils_test.py | 6 -- 17 files changed, 130 insertions(+), 178 deletions(-) diff --git a/examples/postman_echo/debugtalk.py b/examples/postman_echo/debugtalk.py index d28b829b..c0b2aebb 100644 --- a/examples/postman_echo/debugtalk.py +++ b/examples/postman_echo/debugtalk.py @@ -4,6 +4,7 @@ from httprunner import __version__ def get_httprunner_version(): return __version__ + def sum_two(m, n): return m + n @@ -18,3 +19,7 @@ def get_testsuite_config_variables(): def get_app_version(): return [3.1, 3.0] + + +def calculate_two_nums(a, b=1): + return [a + b, b - a] 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 50eb0cc8..5e375e83 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 @@ -1,10 +1,11 @@ -# NOTE: Generated By HttpRunner v3.1.2 +# NOTE: Generated By HttpRunner v3.1.3 # FROM: request_methods/request_with_functions.yml from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseRequestWithFunctions(HttpRunner): + config = ( Config("request with functions") .variables( 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 2d131814..ffc8297c 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 @@ -1,4 +1,4 @@ -# NOTE: Generated By HttpRunner v3.1.2 +# NOTE: Generated By HttpRunner v3.1.3 # FROM: request_methods/request_with_testcase_reference.yml import sys @@ -14,6 +14,7 @@ from request_methods.request_with_functions_test import ( class TestCaseRequestWithTestcaseReference(HttpRunner): + config = ( Config("request with referenced testcase") .variables( diff --git a/examples/postman_echo/request_methods/hardcode_test.py b/examples/postman_echo/request_methods/hardcode_test.py index 70e5e3c9..110c7d9b 100644 --- a/examples/postman_echo/request_methods/hardcode_test.py +++ b/examples/postman_echo/request_methods/hardcode_test.py @@ -1,10 +1,11 @@ -# NOTE: Generated By HttpRunner v3.1.2 +# NOTE: Generated By HttpRunner v3.1.3 # FROM: request_methods/hardcode.yml from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseHardcode(HttpRunner): + config = ( Config("request methods testcase in hardcode") .base_url("https://postman-echo.com") diff --git a/examples/postman_echo/request_methods/request_with_functions_test.py b/examples/postman_echo/request_methods/request_with_functions_test.py index 996eed64..80979440 100644 --- a/examples/postman_echo/request_methods/request_with_functions_test.py +++ b/examples/postman_echo/request_methods/request_with_functions_test.py @@ -1,10 +1,11 @@ -# NOTE: Generated By HttpRunner v3.1.2 +# NOTE: Generated By HttpRunner v3.1.3 # FROM: request_methods/request_with_functions.yml from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseRequestWithFunctions(HttpRunner): + config = ( Config("request methods testcase with functions") .variables( diff --git a/examples/postman_echo/request_methods/request_with_parameters_test.py b/examples/postman_echo/request_methods/request_with_parameters_test.py index 8b1e7ca6..e8a3138e 100644 --- a/examples/postman_echo/request_methods/request_with_parameters_test.py +++ b/examples/postman_echo/request_methods/request_with_parameters_test.py @@ -1,23 +1,24 @@ # NOTE: Generated By HttpRunner v3.1.3 # FROM: request_methods/request_with_parameters.yml + +import pytest +from httprunner import parse_parameters + from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseRequestWithParameters(HttpRunner): - - import pytest - from httprunner.parser import parse_parameters - - param = [ - { - "user_agent": ["iOS/10.1", "iOS/10.2"], - "username-password": "${parameterize(request_methods/account.csv)}", - "app_version": "${get_app_version()}", - } - ] - - @pytest.mark.parametrize("parameters", parse_parameters(param)) + @pytest.mark.parametrize( + "parameters", + parse_parameters( + { + "user_agent": ["iOS/10.1", "iOS/10.2"], + "username-password": "${parameterize(request_methods/account.csv)}", + "app_version": "${get_app_version()}", + } + ), + ) def test_start(self, parameters): super().test_start(parameters) 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 2d57795e..c480236f 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 @@ -1,4 +1,4 @@ -# NOTE: Generated By HttpRunner v3.1.2 +# NOTE: Generated By HttpRunner v3.1.3 # FROM: request_methods/request_with_testcase_reference.yml import sys @@ -14,6 +14,7 @@ from request_methods.request_with_functions_test import ( class TestCaseRequestWithTestcaseReference(HttpRunner): + config = ( Config("request methods testcase: reference testcase") .variables( diff --git a/examples/postman_echo/request_methods/request_with_variables_test.py b/examples/postman_echo/request_methods/request_with_variables_test.py index cacc4621..e40a3636 100644 --- a/examples/postman_echo/request_methods/request_with_variables_test.py +++ b/examples/postman_echo/request_methods/request_with_variables_test.py @@ -1,10 +1,11 @@ -# NOTE: Generated By HttpRunner v3.1.2 +# NOTE: Generated By HttpRunner v3.1.3 # FROM: request_methods/request_with_variables.yml from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseRequestWithVariables(HttpRunner): + config = ( Config("request methods testcase with variables") .variables(**{"foo1": "testcase_config_bar1", "foo2": "testcase_config_bar2"}) diff --git a/examples/postman_echo/request_methods/validate_with_functions_test.py b/examples/postman_echo/request_methods/validate_with_functions_test.py index 4b67bba5..6594631c 100644 --- a/examples/postman_echo/request_methods/validate_with_functions_test.py +++ b/examples/postman_echo/request_methods/validate_with_functions_test.py @@ -1,10 +1,11 @@ -# NOTE: Generated By HttpRunner v3.1.2 +# NOTE: Generated By HttpRunner v3.1.3 # FROM: request_methods/validate_with_functions.yml from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseValidateWithFunctions(HttpRunner): + config = ( Config("request methods testcase: validate with functions") .variables(**{"foo1": "session_bar1"}) diff --git a/examples/postman_echo/request_methods/validate_with_variables_test.py b/examples/postman_echo/request_methods/validate_with_variables_test.py index 07f6d5b3..6ff5b87e 100644 --- a/examples/postman_echo/request_methods/validate_with_variables_test.py +++ b/examples/postman_echo/request_methods/validate_with_variables_test.py @@ -1,10 +1,11 @@ -# NOTE: Generated By HttpRunner v3.1.2 +# NOTE: Generated By HttpRunner v3.1.3 # FROM: request_methods/validate_with_variables.yml from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase class TestCaseValidateWithVariables(HttpRunner): + config = ( Config("request methods testcase: validate with variables") .variables(**{"foo1": "session_bar1"}) diff --git a/httprunner/__init__.py b/httprunner/__init__.py index 70d26337..251d78c7 100644 --- a/httprunner/__init__.py +++ b/httprunner/__init__.py @@ -3,6 +3,7 @@ __description__ = "One-stop solution for HTTP(S) testing." # import firstly for monkey patch if needed from httprunner.ext.locust import main_locusts +from httprunner.parser import parse_parameters from httprunner.runner import HttpRunner from httprunner.testcase import Config, Step, RunRequest, RunTestCase @@ -14,4 +15,5 @@ __all__ = [ "Step", "RunRequest", "RunTestCase", + "parse_parameters", ] diff --git a/httprunner/make.py b/httprunner/make.py index 871d358b..206642a8 100644 --- a/httprunner/make.py +++ b/httprunner/make.py @@ -37,23 +37,31 @@ pytest_files_run_set: Set = set() __TEMPLATE__ = jinja2.Template( """# NOTE: Generated By HttpRunner v{{ version }} # FROM: {{ testcase_path }} + {% if imports_list and diff_levels > 0 %} import sys from pathlib import Path - -sys.path.insert(0, str(Path(__file__) -{% for _ in range(diff_levels) %} -.parent -{% endfor %} -)) +sys.path.insert(0, str(Path(__file__){% for _ in range(diff_levels) %}.parent{% endfor %})) {% endif %} + +{% if parameters %} +import pytest +from httprunner import parse_parameters +{% endif %} + from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase {% for import_str in imports_list %} {{ import_str }} {% endfor %} class {{ class_name }}(HttpRunner): - {{ customization_test_start }} + + {% if parameters %} + @pytest.mark.parametrize('parameters', parse_parameters({{parameters}})) + def test_start(self, parameters): + super().test_start(parameters) + {% endif %} + config = {{ config_chain_style }} teststeps = [ @@ -411,7 +419,7 @@ def make_testcase(testcase: Dict, dir_path: Text = None) -> Text: "class_name": f"TestCase{testcase_cls_name}", "imports_list": imports_list, "config_chain_style": make_config_chain_style(config), - "customization_test_start": make_test_start_style(config), + "parameters": config.get("parameters"), "teststeps_chain_style": [ make_teststep_chain_style(step) for step in teststeps ], @@ -611,22 +619,3 @@ def init_make_parser(subparsers): ) return parser - - -def make_test_start_style(config: Dict) -> Text: - test_start_style = "" - if "parameters" in config.keys(): - params = config["parameters"] - test_start_style = f""" - import pytest - from httprunner.parser import parse_parameters - - param = [{params}] - - @pytest.mark.parametrize('parametrize', parse_parameters(param)) - def test_start(self, parametrize): - super().test_start(parametrize) - """ - else: - pass - return test_start_style diff --git a/httprunner/parser.py b/httprunner/parser.py index 166cc696..f7fd4f25 100644 --- a/httprunner/parser.py +++ b/httprunner/parser.py @@ -1,7 +1,7 @@ import ast import builtins import re -from typing import Any, Set, Text, Callable, List, Dict +from typing import Any, Set, Text, Callable, List, Dict, Union from loguru import logger from sentry_sdk import capture_exception @@ -465,52 +465,44 @@ def parse_variables_mapping( return parsed_variables -def parse_parameters(parameters, variables_mapping=None, functions_mapping=None): +def parse_parameters(parameters: Dict,) -> List[Dict]: """ parse parameters and generate cartesian product. Args: - parameters (list) parameters: parameter name and value in list + parameters (Dict) parameters: parameter name and value mapping parameter value may be in three types: (1) data list, e.g. ["iOS/10.1", "iOS/10.2", "iOS/10.3"] (2) call built-in parameterize function, "${parameterize(account.csv)}" (3) call custom function in debugtalk.py, "${gen_app_version()}" - variables_mapping (dict): variables mapping loaded from testcase config - functions_mapping (dict): functions mapping loaded from debugtalk.py - Returns: list: cartesian product list Examples: - >>> parameters = [ - {"user_agent": ["iOS/10.1", "iOS/10.2", "iOS/10.3"]}, - {"username-password": "${parameterize(account.csv)}"}, - {"app_version": "${gen_app_version()}"} - ] + >>> parameters = { + "user_agent": ["iOS/10.1", "iOS/10.2", "iOS/10.3"], + "username-password": "${parameterize(account.csv)}", + "app_version": "${gen_app_version()}", + } >>> parse_parameters(parameters) """ - variables_mapping = variables_mapping or {} - functions_mapping = functions_mapping or {} - parsed_parameters_list = [] + parsed_parameters_list: List[List[Dict]] = [] # load project_meta functions - from httprunner.loader import load_project_meta + project_meta = loader.load_project_meta("") + functions_mapping = project_meta.functions - project_meta = load_project_meta("") - functions_mapping.update(project_meta.functions) - - parameters = utils.ensure_mapping_format(parameters) for parameter_name, parameter_content in parameters.items(): parameter_name_list = parameter_name.split("-") - if isinstance(parameter_content, list): + if isinstance(parameter_content, List): # (1) data list # e.g. {"app_version": ["2.8.5", "2.8.6"]} # => [{"app_version": "2.8.5", "app_version": "2.8.6"}] # e.g. {"username-password": [["user1", "111111"], ["test2", "222222"]} # => [{"username": "user1", "password": "111111"}, {"username": "user2", "password": "222222"}] - parameter_content_list = [] + parameter_content_list: List[Dict] = [] for parameter_item in parameter_content: if not isinstance(parameter_item, (list, tuple)): # "2.8.5" => ["2.8.5"] @@ -519,24 +511,21 @@ def parse_parameters(parameters, variables_mapping=None, functions_mapping=None) # ["app_version"], ["2.8.5"] => {"app_version": "2.8.5"} # ["username", "password"], ["user1", "111111"] => {"username": "user1", "password": "111111"} parameter_content_dict = dict(zip(parameter_name_list, parameter_item)) - parameter_content_list.append(parameter_content_dict) - else: + + elif isinstance(parameter_content, Text): # (2) & (3) - parsed_variables_mapping = parse_variables_mapping( - variables_mapping, functions_mapping + parsed_parameter_content: List = parse_data( + parameter_content, {}, functions_mapping ) - parsed_parameter_content = parse_data( - parameter_content, parsed_variables_mapping, functions_mapping - ) - if not isinstance(parsed_parameter_content, list): + if not isinstance(parsed_parameter_content, List): raise exceptions.ParamsError( - f"{parsed_parameter_content} parameters syntax error!" + f"parameters content should be in List type, got {parsed_parameter_content} for {parameter_content}" ) - parameter_content_list = [] + parameter_content_list: List[Dict] = [] for parameter_item in parsed_parameter_content: - if isinstance(parameter_item, dict): + if isinstance(parameter_item, Dict): # get subset by parameter name # {"app_version": "${gen_app_version()}"} # gen_app_version() => [{'app_version': '2.8.5'}, {'app_version': '2.8.6'}] @@ -545,20 +534,39 @@ def parse_parameters(parameters, variables_mapping=None, functions_mapping=None) # {"username": "user1", "password": "111111"}, # {"username": "user2", "password": "222222"} # ] - parameter_dict = { + parameter_dict: Dict = { key: parameter_item[key] for key in parameter_name_list } - # elif isinstance(parameter_item, (list, tuple)): - # # {"username-password": "${get_account()}"} - # # get_account() => [("user1", "111111"), ("user2", "222222")] - # parameter_dict = dict(zip(parameter_name_list, parameter_item)) + elif isinstance(parameter_item, (List, tuple)): + if len(parameter_name_list) == len(parameter_item): + # {"username-password": "${get_account()}"} + # get_account() => [("user1", "111111"), ("user2", "222222")] + parameter_dict = dict(zip(parameter_name_list, parameter_item)) + else: + raise exceptions.ParamsError( + f"parameter names length are not equal to value length.\n" + f"parameter names: {parameter_name_list}\n" + f"parameter values: {parameter_item}" + ) elif len(parameter_name_list) == 1: # {"user_agent": "${get_user_agent()}"} # get_user_agent() => ["iOS/10.1", "iOS/10.2"] + # parameter_dict will get: {"user_agent": "iOS/10.1", "user_agent": "iOS/10.2"} parameter_dict = {parameter_name_list[0]: parameter_item} + else: + raise exceptions.ParamsError( + f"Invalid parameter names and values:\n" + f"parameter names: {parameter_name_list}\n" + f"parameter values: {parameter_item}" + ) parameter_content_list.append(parameter_dict) + else: + raise exceptions.ParamsError( + f"parameter content should be List or Text(variables or functions call), got {parameter_content}" + ) + parsed_parameters_list.append(parameter_content_list) return utils.gen_cartesian_product(*parsed_parameters_list) diff --git a/httprunner/utils.py b/httprunner/utils.py index 597c728c..eeb7e0a0 100644 --- a/httprunner/utils.py +++ b/httprunner/utils.py @@ -6,7 +6,7 @@ import platform import uuid from multiprocessing import Queue import itertools -from typing import Dict, List, Any +from typing import Dict, List, Any, Union, Text import sentry_sdk from loguru import logger @@ -223,42 +223,7 @@ def is_support_multiprocessing() -> bool: return False -def ensure_mapping_format(variables): - """ ensure variables are in mapping format. - - Args: - variables (list/dict): original variables - - Returns: - dict: ensured variables in dict format - - Examples: - >>> variables = [ - {"a": 1}, - {"b": 2} - ] - >>> print(ensure_mapping_format(variables)) - { - "a": 1, - "b": 2 - } - - """ - if isinstance(variables, list): - variables_dict = {} - for map_dict in variables: - variables_dict.update(map_dict) - - return variables_dict - - elif isinstance(variables, dict): - return variables - - else: - raise exceptions.ParamsError("variables format error!") - - -def gen_cartesian_product(*args): +def gen_cartesian_product(*args: List[Dict]) -> List[Dict]: """ generate cartesian product for lists Args: diff --git a/tests/make_test.py b/tests/make_test.py index 1cda6a60..56199b8f 100644 --- a/tests/make_test.py +++ b/tests/make_test.py @@ -1,6 +1,7 @@ import os import unittest +from httprunner import loader from httprunner.make import ( main_make, convert_testcase_path, @@ -9,9 +10,7 @@ from httprunner.make import ( make_teststep_chain_style, pytest_files_run_set, ensure_file_abs_path_valid, - make_test_start_style, ) -from httprunner import loader class TestMake(unittest.TestCase): @@ -215,24 +214,3 @@ from request_methods.request_with_functions_test import ( teststep_chain_style, """Step(RunRequest("get with params").with_variables(**{'foo1': 'bar1', 'foo2': 123, 'sum_v': '${sum_two(1, 2)}'}).get("/get").with_params(**{'foo1': '$foo1', 'foo2': '$foo2', 'sum_v': '$sum_v'}).with_headers(**{'User-Agent': 'HttpRunner/${get_httprunner_version()}'}).extract().with_jmespath('body.args.foo1', 'session_foo1').with_jmespath('body.args.foo2', 'session_foo2').validate().assert_equal("status_code", 200).assert_equal("body.args.sum_v", "3"))""", ) - - def test_make_test_start_style(self): - params = { - "user_agent": ["iOS/10.1", "iOS/10.2"], - "username-password": "${parameterize(request_methods/account.csv)}", - "app_version": "${get_app_version()}", - } - config = {"parameters": params} - self.assertEqual( - make_test_start_style(config), - f""" - import pytest - from httprunner.parser import parse_parameters - - param = [{params}] - - @pytest.mark.parametrize('parametrize', parse_parameters(param)) - def test_start(self, parametrize): - super().test_start(parametrize) - """, - ) diff --git a/tests/parser_test.py b/tests/parser_test.py index bf11f154..e1eef7fa 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -1,9 +1,10 @@ +import os import time import unittest from httprunner import parser from httprunner.exceptions import VariableNotFound, FunctionNotFound -from httprunner.parser import regex_findall_variables +from httprunner.loader import load_project_meta class TestParserBasic(unittest.TestCase): @@ -27,17 +28,19 @@ class TestParserBasic(unittest.TestCase): self.assertEqual(parser.parse_string_value("${func}"), "${func}") def test_regex_findall_variables(self): - self.assertEqual(regex_findall_variables("$variable"), ["variable"]) - self.assertEqual(regex_findall_variables("${variable}123"), ["variable"]) - self.assertEqual(regex_findall_variables("/blog/$postid"), ["postid"]) - self.assertEqual(regex_findall_variables("/$var1/$var2"), ["var1", "var2"]) - self.assertEqual(regex_findall_variables("abc"), []) - self.assertEqual(regex_findall_variables("Z:2>1*0*1+1$a"), ["a"]) - self.assertEqual(regex_findall_variables("Z:2>1*0*1+1$$a"), []) - self.assertEqual(regex_findall_variables("Z:2>1*0*1+1$$$a"), ["a"]) - self.assertEqual(regex_findall_variables("Z:2>1*0*1+1$$$$a"), []) - self.assertEqual(regex_findall_variables("Z:2>1*0*1+1$$a$b"), ["b"]) - self.assertEqual(regex_findall_variables("Z:2>1*0*1+1$$a$$b"), []) + self.assertEqual(parser.regex_findall_variables("$variable"), ["variable"]) + self.assertEqual(parser.regex_findall_variables("${variable}123"), ["variable"]) + self.assertEqual(parser.regex_findall_variables("/blog/$postid"), ["postid"]) + self.assertEqual( + parser.regex_findall_variables("/$var1/$var2"), ["var1", "var2"] + ) + self.assertEqual(parser.regex_findall_variables("abc"), []) + self.assertEqual(parser.regex_findall_variables("Z:2>1*0*1+1$a"), ["a"]) + self.assertEqual(parser.regex_findall_variables("Z:2>1*0*1+1$$a"), []) + self.assertEqual(parser.regex_findall_variables("Z:2>1*0*1+1$$$a"), ["a"]) + self.assertEqual(parser.regex_findall_variables("Z:2>1*0*1+1$$$$a"), []) + self.assertEqual(parser.regex_findall_variables("Z:2>1*0*1+1$$a$b"), ["b"]) + self.assertEqual(parser.regex_findall_variables("Z:2>1*0*1+1$$a$$b"), []) def test_extract_variables(self): self.assertEqual(parser.extract_variables("$var"), {"var"}) @@ -454,23 +457,22 @@ class TestParserBasic(unittest.TestCase): self.assertEqual(parsed_testcase["headers"]["sum"], 3) def test_parse_parameters_testcase(self): - variables = { - "user_agent": "chrome", - "sum": 5, + parameters = { + "user_agent": ["iOS/10.1", "iOS/10.2"], + "username-password": "${parameterize(request_methods/account.csv)}", + "sum": "${calculate_two_nums(1, 2)}", } - param = [ - { - "user_agent": ["iOS/10.1", "iOS/10.2"], - "username-password": "${parameterize(request_methods/account.csv)}", - "sum": "${add_two_nums(1, 2)}", - } - ] + load_project_meta( + os.path.join( + os.path.dirname(os.path.dirname(__file__)), + "examples", + "postman_echo", + "request_methods", + ), + ) + parsed_params = parser.parse_parameters(parameters) + self.assertEqual(len(parsed_params), 2 * 3 * 2) - functions = { - "add_two_nums": lambda a, b=1: [a + b, b - a], - } - - parsed_params = parser.parse_parameters(param, variables, functions) self.assertIn( { "username": "test1", diff --git a/tests/utils_test.py b/tests/utils_test.py index 4b583929..444c4f3b 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -126,12 +126,6 @@ class TestUtils(unittest.TestCase): {"base_url": "https://httpbin.org", "foo1": "bar1"}, ) - def test_ensure_mapping_format(self): - map_list = [{"a": 1}, {"b": 2}] - ordered_dict = utils.ensure_mapping_format(map_list) - self.assertIsInstance(ordered_dict, dict) - self.assertIn("a", ordered_dict) - def test_cartesian_product_one(self): parameters_content_list = [[{"a": 1}, {"a": 2}]] product_list = utils.gen_cartesian_product(*parameters_content_list)