From d0128bf182d040e507b73b91fe12eb9d7d01775c Mon Sep 17 00:00:00 2001 From: debugtalk Date: Sun, 30 Sep 2018 00:20:10 +0800 Subject: [PATCH] refactor pipline --- httprunner/api.py | 336 ++++++++++++----------- httprunner/context.py | 5 +- httprunner/loader.py | 185 ++++++------- httprunner/locusts.py | 2 +- httprunner/parser.py | 40 ++- httprunner/report.py | 2 +- httprunner/templates/locustfile_template | 5 +- tests/test_api.py | 125 ++++----- tests/test_context.py | 5 +- tests/test_loader.py | 146 ++++++---- tests/test_parser.py | 7 +- tests/test_runner.py | 6 +- 12 files changed, 451 insertions(+), 413 deletions(-) diff --git a/httprunner/api.py b/httprunner/api.py index d0ce9c1c..abbd1bdd 100644 --- a/httprunner/api.py +++ b/httprunner/api.py @@ -8,6 +8,121 @@ from httprunner import (exceptions, loader, logger, parser, report, runner, utils, validator) +def parse_tests(testcases, variables_mapping=None): + """ parse testcases configs, including variables/parameters/name/request. + + Args: + testcases (list): testcase list, with config unparsed. + [ + { # testcase data structure + "config": { + "name": "desc1", + "path": "testcase1_path", + "variables": [], # optional + "request": {} # optional + "refs": { + "debugtalk": { + "variables": {}, + "functions": {} + }, + "env": {}, + "def-api": {}, + "def-testcase": {} + } + }, + "teststeps": [ + # teststep data structure + { + 'name': 'test step desc2', + 'variables': [], # optional + 'extract': [], # optional + 'validate': [], + 'request': {}, + 'function_meta': {} + }, + teststep2 # another teststep dict + ] + }, + testcase_dict_2 # another testcase dict + ] + variables_mapping (dict): if variables_mapping is specified, it will override variables in config block. + + Returns: + list: parsed testcases list, with config variables/parameters/name/request parsed. + + """ + # exception_stage = "parse tests" + variables_mapping = variables_mapping or {} + parsed_testcases_list = [] + + for testcase in testcases: + testcase_config = testcase.setdefault("config", {}) + project_mapping = testcase_config.pop( + "refs", + { + "debugtalk": { + "variables": {}, + "functions": {} + }, + "env": {}, + "def-api": {}, + "def-testcase": {} + } + ) + + # parse config parameters + config_parameters = testcase_config.pop("parameters", []) + cartesian_product_parameters_list = parser.parse_parameters( + config_parameters, + project_mapping["debugtalk"]["variables"], + project_mapping["debugtalk"]["functions"] + ) or [{}] + + for parameter_mapping in cartesian_product_parameters_list: + testcase_dict = copy.deepcopy(testcase) + config = testcase_dict.get("config") + + # parse config variables + raw_config_variables = config.get("variables", []) + parsed_config_variables = parser.parse_data( + raw_config_variables, + project_mapping["debugtalk"]["variables"], + project_mapping["debugtalk"]["functions"] + ) + + # priority: passed in > debugtalk.py > parameters > variables + # override variables mapping with parameters mapping + config_variables = utils.override_mapping_list( + parsed_config_variables, parameter_mapping) + # merge debugtalk.py module variables + config_variables.update(project_mapping["debugtalk"]["variables"]) + # override variables mapping with passed in variables_mapping + config_variables = utils.override_mapping_list( + config_variables, variables_mapping) + + testcase_dict["config"]["variables"] = config_variables + + # parse config name + testcase_dict["config"]["name"] = parser.parse_data( + testcase_dict["config"].get("name", ""), + config_variables, + project_mapping["debugtalk"]["functions"] + ) + + # parse config request + testcase_dict["config"]["request"] = parser.parse_data( + testcase_dict["config"].get("request", {}), + config_variables, + project_mapping["debugtalk"]["functions"] + ) + + # put loaded project functions to config + testcase_dict["config"]["functions"] = project_mapping["debugtalk"]["functions"] + parsed_testcases_list.append(testcase_dict) + + return parsed_testcases_list + + class HttpRunner(object): def __init__(self, **kwargs): @@ -20,7 +135,6 @@ class HttpRunner(object): resultclass (class): HtmlTestResult or TextTestResult failfast (bool): False/True, stop the test run on the first error or failure. http_client_session (instance): requests.Session(), or locust.client.Session() instance. - dot_env_path (str): .env file path. Attributes: project_mapping (dict): save project loaded api/testcases, environments and debugtalk.py module. @@ -36,154 +150,16 @@ class HttpRunner(object): """ self.exception_stage = "initialize HttpRunner()" - loader.reset_loader() - loader.dot_env_path = kwargs.pop("dot_env_path", None) self.http_client_session = kwargs.pop("http_client_session", None) kwargs.setdefault("resultclass", report.HtmlTestResult) self.unittest_runner = unittest.TextTestRunner(**kwargs) self.test_loader = unittest.TestLoader() - def load_tests(self, path_or_testcases): - """ load testcases, extend and merge with api/testcase definitions. - - Args: - path_or_testcases (str/dict/list): YAML/JSON testcase file path or testcase list - path (str): testcase file/folder path - testcases (dict/list): testcase dict or list of testcases - - Returns: - list: valid testcases list. - - [ - # testcase data structure - { - "config": { - "name": "desc1", - "path": "", # optional - "variables": [], # optional - "request": {} # optional - }, - "teststeps": [ - # teststep data structure - { - 'name': 'test step desc2', - 'variables': [], # optional - 'extract': [], # optional - 'validate': [], - 'request': {}, - 'function_meta': {} - }, - teststep2 # another teststep dict - ] - }, - {} # another testcase dict - ] - - """ - self.exception_stage = "load tests" - if validator.is_testcases(path_or_testcases): - # TODO: refactor - if isinstance(path_or_testcases, list): - for testcase in path_or_testcases: - try: - test_path = os.path.dirname(testcase["config"]["path"]) - except KeyError: - test_path = os.getcwd() - loader.load_project_tests(test_path) - else: - try: - test_path = os.path.dirname(path_or_testcases["config"]["path"]) - except KeyError: - test_path = os.getcwd() - loader.load_project_tests(test_path) - - testcases = path_or_testcases - else: - testcases = loader.load_testcases(path_or_testcases) - - self.project_mapping = loader.project_mapping - - if not testcases: - raise exceptions.TestcaseNotFound - - if isinstance(testcases, dict): - testcases = [testcases] - - return testcases - - def parse_tests(self, testcases, variables_mapping=None): - """ parse testcases configs, including variables/parameters/name/request. - - Args: - testcases (list): testcase list, with config unparsed. - variables_mapping (dict): if variables_mapping is specified, it will override variables in config block. - - Returns: - list: parsed testcases list, with config variables/parameters/name/request parsed. - - """ - self.exception_stage = "parse tests" - variables_mapping = variables_mapping or {} - - parsed_testcases_list = [] - for testcase in testcases: - # parse config parameters - config_parameters = testcase.setdefault("config", {}).pop("parameters", []) - cartesian_product_parameters_list = parser.parse_parameters( - config_parameters, - self.project_mapping["debugtalk"]["variables"], - self.project_mapping["debugtalk"]["functions"] - ) or [{}] - - for parameter_mapping in cartesian_product_parameters_list: - testcase_dict = copy.deepcopy(testcase) - config = testcase_dict.setdefault("config", {}) - - # parse config variables - raw_config_variables = config.get("variables", []) - parsed_config_variables = parser.parse_data( - raw_config_variables, - self.project_mapping["debugtalk"]["variables"], - self.project_mapping["debugtalk"]["functions"] - ) - - # priority: passed in > debugtalk.py > parameters > variables - # override variables mapping with parameters mapping - config_variables = utils.override_mapping_list( - parsed_config_variables, parameter_mapping) - # merge debugtalk.py module variables - config_variables.update(self.project_mapping["debugtalk"]["variables"]) - # override variables mapping with passed in variables_mapping - config_variables = utils.override_mapping_list( - config_variables, variables_mapping) - - testcase_dict["config"]["variables"] = config_variables - - # parse config name - testcase_dict["config"]["name"] = parser.parse_data( - testcase_dict["config"].get("name", ""), - config_variables, - self.project_mapping["debugtalk"]["functions"] - ) - - # parse config request - testcase_dict["config"]["request"] = parser.parse_data( - testcase_dict["config"].get("request", {}), - config_variables, - self.project_mapping["debugtalk"]["functions"] - ) - - # put loaded project functions to config - testcase_dict["config"]["functions"] = self.project_mapping["debugtalk"]["functions"] - parsed_testcases_list.append(testcase_dict) - - return parsed_testcases_list - - def add_tests(self, testcases): + def _add_tests(self, testcases): """ initialize testcase with Runner() and add to test suite. Args: - testcases (list): testcases list + testcases (list): parsed testcases list Returns: tuple: unittest.TestSuite() @@ -240,7 +216,7 @@ class HttpRunner(object): return test_suite - def run_tests(self, test_suite): + def _run_suite(self, test_suite): """ run tests in test_suite Args: @@ -262,7 +238,7 @@ class HttpRunner(object): return tests_results - def aggregate(self, tests_results): + def _aggregate(self, tests_results): """ aggregate results Args: @@ -295,45 +271,77 @@ class HttpRunner(object): self.summary["details"].append(testcase_summary) - def run(self, path_or_testcases, mapping=None): + def run_tests(self, testcases, mapping=None): """ start to run test with variables mapping. Args: - path_or_testcases (str/list/dict): YAML/JSON testcase file path or testcase list - path: path could be in several type - - absolute/relative file path - - absolute/relative folder path - - list/set container with file(s) and/or folder(s) - testcases: testcase dict or list of testcases - - (dict) testset_dict - - (list) list of testset_dict - [ - testset_dict_1, - testset_dict_2 + testcases (list): list of testcase_dict, each testcase is corresponding to a YAML/JSON file + [ + { # testcase data structure + "config": { + "name": "desc1", + "path": "testcase1_path", + "variables": [], # optional + "request": {} # optional + "refs": { + "debugtalk": { + "variables": {}, + "functions": {} + }, + "env": {}, + "def-api": {}, + "def-testcase": {} + } + }, + "teststeps": [ + # teststep data structure + { + 'name': 'test step desc2', + 'variables': [], # optional + 'extract': [], # optional + 'validate': [], + 'request': {}, + 'function_meta': {} + }, + teststep2 # another teststep dict ] - mapping (dict): if mapping specified, it will override variables in config block. + }, + testcase_dict_2 # another testcase dict + ] + mapping (dict): if mapping is specified, it will override variables in config block. Returns: instance: HttpRunner() instance """ - # loader - testcases_list = self.load_tests(path_or_testcases) - # parser - parsed_testcases_list = self.parse_tests(testcases_list) + parsed_testcases_list = parse_tests(testcases, mapping) # initialize - test_suite = self.add_tests(parsed_testcases_list) + test_suite = self._add_tests(parsed_testcases_list) - # running tests - results = self.run_tests(test_suite) + # running test suite + results = self._run_suite(test_suite) # aggregate - self.aggregate(results) + self._aggregate(results) return self + def run(self, testcase_path, mapping=None): + """ main entrance, run testcase path with variables mapping. + + Args: + testcase_path (str/list): testcase file/foler path. + mapping (dict): if mapping is specified, it will override variables in config block. + + Returns: + instance: HttpRunner() instance + + """ + testcases = loader.load_tests(testcase_path) + return self.run_tests(testcases) + def gen_html_report(self, html_report_name=None, html_report_template=None): """ generate html report and return report path. diff --git a/httprunner/context.py b/httprunner/context.py index 24fdbab2..98e7ebce 100644 --- a/httprunner/context.py +++ b/httprunner/context.py @@ -183,10 +183,7 @@ class Context(object): """ # TODO: move comparator uniform to init_test_suites comparator = utils.get_uniform_comparator(validator_dict["comparator"]) - validate_func = self.TESTCASE_SHARED_FUNCTIONS_MAPPING.get(comparator) - - if not validate_func: - raise exceptions.FunctionNotFound("comparator not found: {}".format(comparator)) + validate_func = parser.get_mapping_function(comparator, self.TESTCASE_SHARED_FUNCTIONS_MAPPING) check_item = validator_dict["check"] check_value = validator_dict["check_value"] diff --git a/httprunner/loader.py b/httprunner/loader.py index 0c24315c..8cabaed4 100644 --- a/httprunner/loader.py +++ b/httprunner/loader.py @@ -10,24 +10,6 @@ import yaml from httprunner import built_in, exceptions, logger, parser, utils, validator from httprunner.compat import OrderedDict -sys.path.insert(0, os.getcwd()) - -project_mapping = { - "debugtalk": { - "variables": {}, - "functions": {} - }, - "env": {}, - "def-api": {}, - "def-testcase": {} -} -""" dict: save project loaded api/testcases definitions, environments and debugtalk.py module. -""" - -dot_env_path = None -testcases_cache_mapping = {} -project_working_directory = os.getcwd() - ############################################################################### ## file loader @@ -161,9 +143,11 @@ def load_folder_files(folder_path, recursive=True): return file_list -def load_dot_env_file(): - """ load .env file, .env file should be located in project working directory by default. - If dot_env_path is specified, it will be loaded instead. +def load_dot_env_file(dot_env_path): + """ load .env file. + + Args: + dot_env_path (str): .env file path Returns: dict: environment variables mapping @@ -175,21 +159,15 @@ def load_dot_env_file(): } Raises: - exceptions.FileFormatError: If env file format is invalid. + exceptions.FileFormatError: If .env file format is invalid. """ - path = dot_env_path or os.path.join(project_working_directory, ".env") - if not os.path.isfile(path): - if dot_env_path: - logger.log_error(".env file not exist: {}".format(dot_env_path)) - sys.exit(1) - else: - logger.log_debug(".env file not exist in: {}".format(project_working_directory)) - return {} + if not os.path.isfile(dot_env_path): + raise exceptions.FileNotFound(".env file path is not exist.") - logger.log_info("Loading environment variables from {}".format(path)) + logger.log_info("Loading environment variables from {}".format(dot_env_path)) env_variables_mapping = {} - with io.open(path, 'r', encoding='utf-8') as fp: + with io.open(dot_env_path, 'r', encoding='utf-8') as fp: for line in fp: # maxsplit=1 if "=" in line: @@ -201,9 +179,7 @@ def load_dot_env_file(): env_variables_mapping[variable.strip()] = value.strip() - project_mapping["env"] = env_variables_mapping utils.set_os_environ(env_variables_mapping) - return env_variables_mapping @@ -281,13 +257,15 @@ def load_builtin_module(): """ load built_in module """ built_in_module = load_python_module(built_in) - project_mapping["debugtalk"] = built_in_module + return built_in_module def load_debugtalk_module(): - """ load project debugtalk.py module and merge with builtin module. + """ load project debugtalk.py module debugtalk.py should be located in project working directory. - variables and functions mapping for debugtalk.py + + Returns: + dict: debugtalk module mapping { "variables": {}, "functions": {} @@ -297,10 +275,7 @@ def load_debugtalk_module(): # load debugtalk.py module imported_module = importlib.import_module("debugtalk") debugtalk_module = load_python_module(imported_module) - - # override built_in module with debugtalk.py module - project_mapping["debugtalk"]["variables"].update(debugtalk_module["variables"]) - project_mapping["debugtalk"]["functions"].update(debugtalk_module["functions"]) + return debugtalk_module def get_module_item(module_mapping, item_type, item_name): @@ -340,12 +315,11 @@ def get_module_item(module_mapping, item_type, item_name): ## testcase loader ############################################################################### -def _load_test_file(file_path): +def _load_test_file(file_path, project_mapping): """ load testcase file or testsuite file Args: file_path (str): absolute valid file path. file_path should be in the following format: - [ { "config": { @@ -376,6 +350,7 @@ def _load_test_file(file_path): } } ] + project_mapping (dict): project_mapping Returns: dict: testcase dict @@ -406,7 +381,7 @@ def _load_test_file(file_path): def extend_api_definition(block): ref_call = block["api"] - def_block = _get_block_by_name(ref_call, "def-api") + def_block = _get_block_by_name(ref_call, "def-api", project_mapping) _extend_block(block, def_block) # reference api @@ -417,7 +392,7 @@ def _load_test_file(file_path): # reference testcase elif "suite" in test_block: # TODO: replace suite with testcase ref_call = test_block["suite"] - block = _get_block_by_name(ref_call, "def-testcase") + block = _get_block_by_name(ref_call, "def-testcase", project_mapping) # TODO: bugfix lost block config variables for teststep in block["teststeps"]: if "api" in teststep: @@ -436,13 +411,14 @@ def _load_test_file(file_path): return testcase -def _get_block_by_name(ref_call, ref_type): +def _get_block_by_name(ref_call, ref_type, project_mapping): """ get test content by reference name. Args: ref_call (str): call function. e.g. api_v1_Account_Login_POST($UserName, $Password) ref_type (enum): "def-api" or "def-testcase" + project_mapping (dict): project_mapping Returns: dict: api/testcase definition. @@ -454,7 +430,7 @@ def _get_block_by_name(ref_call, ref_type): function_meta = parser.parse_function(ref_call) func_name = function_meta["func_name"] call_args = function_meta["args"] - block = _get_test_definition(func_name, ref_type) + block = _get_test_definition(func_name, ref_type, project_mapping) def_args = block.get("function_meta", {}).get("args", []) if len(call_args) != len(def_args): @@ -477,12 +453,13 @@ def _get_block_by_name(ref_call, ref_type): return block -def _get_test_definition(name, ref_type): +def _get_test_definition(name, ref_type, project_mapping): """ get expected api or testcase. Args: name (str): api or testcase name ref_type (enum): "def-api" or "def-testcase" + project_mapping (dict): project_mapping Returns: dict: expected api/testcase info if found. @@ -764,7 +741,6 @@ def load_api_folder(api_folder_path): api_dict["function_meta"] = function_meta api_definition_mapping[func_name] = api_dict - project_mapping["def-api"] = api_definition_mapping return api_definition_mapping @@ -842,29 +818,9 @@ def load_test_folder(test_folder_path): # key == "test": testcase["teststeps"].append(block) - project_mapping["def-testcase"] = test_definition_mapping return test_definition_mapping -def reset_loader(): - """ reset project mapping. - """ - global project_working_directory - project_working_directory = os.getcwd() - - global dot_env_path - dot_env_path = None - - project_mapping["debugtalk"] = { - "variables": {}, - "functions": {} - } - project_mapping["env"] = {} - project_mapping["def-api"] = {} - project_mapping["def-testcase"] = {} - testcases_cache_mapping.clear() - - def locate_debugtalk_py(start_path): """ locate debugtalk.py file. @@ -879,57 +835,98 @@ def locate_debugtalk_py(start_path): return None -def load_project_tests(test_path): +def load_project_tests(test_path, dot_env_path=None): """ load api, testcases, .env, builtin module and debugtalk.py. api/testcases folder is relative to project_working_directory Args: test_path (str): test file/folder path, locate pwd from this path. + dot_env_path (str): specified .env file path + + Returns: + dict: project loaded api/testcases definitions, environments and debugtalk.py module. """ - global project_working_directory - - reset_loader() - load_builtin_module() + project_mapping = {} debugtalk_path = locate_debugtalk_py(test_path) # locate PWD with debugtalk.py path if debugtalk_path: # The folder contains debugtalk.py will be treated as PWD. - # add PWD to sys.path project_working_directory = os.path.dirname(debugtalk_path) else: - # debugtalk.py not found, use os.getcwd() as PWD. + # debugtalk.py is not found, use os.getcwd() as PWD. project_working_directory = os.getcwd() # load .env - load_dot_env_file() + dot_env_path = dot_env_path or os.path.join(project_working_directory, ".env") + if os.path.isfile(dot_env_path): + project_mapping["env"] = load_dot_env_file(dot_env_path) + else: + project_mapping["env"] = {} # load debugtalk.py if debugtalk_path: + # add PWD to sys.path sys.path.insert(0, project_working_directory) - load_debugtalk_module() + project_mapping["debugtalk"] = load_debugtalk_module() + else: + project_mapping["debugtalk"] = { + "variables": {}, + "functions": {} + } - load_api_folder(os.path.join(project_working_directory, "api")) + project_mapping["def-api"] = load_api_folder(os.path.join(project_working_directory, "api")) # TODO: replace suite with testcases - load_test_folder(os.path.join(project_working_directory, "suite")) + project_mapping["def-testcase"] = load_test_folder(os.path.join(project_working_directory, "suite")) + + return project_mapping -def load_testcases(path): +def load_tests(path, dot_env_path=None): """ load testcases from file path, extend and merge with api/testcase definitions. Args: - path (str): testcase file/foler path. + path (str/list): testcase file/foler path. path could be in several types: - absolute/relative file path - absolute/relative folder path - list/set container with file(s) and/or folder(s) + dot_env_path (str): specified .env file path Returns: list: testcases list, each testcase is corresponding to a file [ - testcase_dict_1, - testcase_dict_2 + { # testcase data structure + "config": { + "name": "desc1", + "path": "testcase1_path", + "variables": [], # optional + "request": {} # optional + "refs": { + "debugtalk": { + "variables": {}, + "functions": {} + }, + "env": {}, + "def-api": {}, + "def-testcase": {} + } + }, + "teststeps": [ + # teststep data structure + { + 'name': 'test step desc2', + 'variables': [], # optional + 'extract': [], # optional + 'validate': [], + 'request': {}, + 'function_meta': {} + }, + teststep2 # another teststep dict + ] + }, + testcase_dict_2 # another testcase dict ] """ @@ -937,7 +934,7 @@ def load_testcases(path): testcases_list = [] for file_path in set(path): - testcases = load_testcases(file_path) + testcases = load_tests(file_path) if not testcases: continue testcases_list.extend(testcases) @@ -952,24 +949,18 @@ def load_testcases(path): if not os.path.isabs(path): path = os.path.join(os.getcwd(), path) - if path not in testcases_cache_mapping: - load_project_tests(path) - else: - return testcases_cache_mapping[path] - if os.path.isdir(path): files_list = load_folder_files(path) - testcases_list = load_testcases(files_list) + testcases_list = load_tests(files_list) elif os.path.isfile(path): try: - testcase = _load_test_file(path) - if testcase["teststeps"]: - testcases_list = [testcase] - else: - testcases_list = [] + project_mapping = load_project_tests(path, dot_env_path) + testcase = _load_test_file(path, project_mapping) + testcase["config"]["path"] = path + testcase["config"]["refs"] = project_mapping + testcases_list = [testcase] except exceptions.FileFormatError: testcases_list = [] - testcases_cache_mapping[path] = testcases_list return testcases_list diff --git a/httprunner/locusts.py b/httprunner/locusts.py index 4f7d2adb..b1532229 100644 --- a/httprunner/locusts.py +++ b/httprunner/locusts.py @@ -40,7 +40,7 @@ def gen_locustfile(testcase_file_path): "templates", "locustfile_template" ) - testcases = loader.load_testcases(testcase_file_path) + testcases = loader.load_tests(testcase_file_path) host = testcases[0].get("config", {}).get("request", {}).get("base_url", "") with io.open(template_path, encoding='utf-8') as template: diff --git a/httprunner/parser.py b/httprunner/parser.py index 58827ff8..4a467752 100644 --- a/httprunner/parser.py +++ b/httprunner/parser.py @@ -1,6 +1,7 @@ # encoding: utf-8 import ast +import copy import os import re @@ -325,6 +326,34 @@ def parse_parameters(parameters, variables_mapping, functions_mapping): ## parse content with variables and functions mapping ############################################################################### +def get_builtin_item(item_type, item_name): + """ + + Args: + item_type (enum): "variables" or "functions" + item_name (str): variable name or function name + + Returns: + variable or function with the name of item_name + + """ + # override built_in module with debugtalk.py module + from httprunner import loader + built_in_module = loader.load_builtin_module() + + if item_type == "variables": + try: + return built_in_module["variables"][item_name] + except KeyError: + raise exceptions.VariableNotFound("{} is not found.".format(item_name)) + else: + # item_type == "functions": + try: + return built_in_module["functions"][item_name] + except KeyError: + raise exceptions.FunctionNotFound("{} is not found.".format(item_name)) + + def get_mapping_variable(variable_name, variables_mapping): """ get variable from variables_mapping. @@ -339,10 +368,10 @@ def get_mapping_variable(variable_name, variables_mapping): exceptions.VariableNotFound: variable is not found. """ - try: + if variable_name in variables_mapping: return variables_mapping[variable_name] - except KeyError: - raise exceptions.VariableNotFound("{} is not found.".format(variable_name)) + else: + return get_builtin_item("variables", variable_name) def get_mapping_function(function_name, functions_mapping): @@ -363,6 +392,11 @@ def get_mapping_function(function_name, functions_mapping): if function_name in functions_mapping: return functions_mapping[function_name] + try: + return get_builtin_item("functions", function_name) + except exceptions.FunctionNotFound: + pass + try: # check if builtin functions item_func = eval(function_name) diff --git a/httprunner/report.py b/httprunner/report.py index 607a8422..b3b3300d 100644 --- a/httprunner/report.py +++ b/httprunner/report.py @@ -95,7 +95,7 @@ def render_html_report(summary, html_report_name=None, html_report_template=None logger.log_info("Start to render Html report ...") logger.log_debug("render data: {}".format(summary)) - report_dir_path = os.path.join(loader.project_working_directory, "reports") + report_dir_path = os.path.join(os.getcwd(), "reports") start_at_timestamp = int(summary["time"]["start_at"]) summary["time"]["start_datetime"] = datetime.fromtimestamp(start_at_timestamp).strftime('%Y-%m-%d %H:%M:%S') if html_report_name: diff --git a/httprunner/templates/locustfile_template b/httprunner/templates/locustfile_template index 7635f3c4..9b7c1924 100644 --- a/httprunner/templates/locustfile_template +++ b/httprunner/templates/locustfile_template @@ -2,16 +2,17 @@ import zmq from locust import HttpLocust, TaskSet, task from httprunner import LocustRunner +from httprunner.loader import load_tests class WebPageTasks(TaskSet): def on_start(self): self.test_runner = LocustRunner(self.client) - self.file_path = self.locust.file_path + self.testcases = loader.load_tests(self.locust.file_path) @task def test_specified_scenario(self): - self.test_runner.run(self.file_path) + self.test_runner.run(self.testcases) class WebPageUser(HttpLocust): diff --git a/tests/test_api.py b/tests/test_api.py index ad053113..96ce9e5f 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -2,7 +2,7 @@ import os import shutil import time -from httprunner import HttpRunner, LocustRunner, loader +from httprunner import HttpRunner, LocustRunner, api, loader, parser from locust import HttpLocust from tests.api_server import HTTPBIN_SERVER from tests.base import ApiServerUnittest @@ -11,25 +11,22 @@ from tests.base import ApiServerUnittest class TestHttpRunner(ApiServerUnittest): def setUp(self): - self.testset_path = "tests/data/demo_testset_cli.yml" + self.testcase_cli_path = "tests/data/demo_testset_cli.yml" self.testcase_file_path_list = [ os.path.join( os.getcwd(), 'tests/data/demo_testset_hardcode.yml'), os.path.join( os.getcwd(), 'tests/data/demo_testset_hardcode.json') ] - self.testcase = { - 'name': 'testset description', + self.testcases = [{ 'config': { - 'name': 'testset description', + 'name': 'testcase description', 'request': { 'base_url': '', 'headers': {'User-Agent': 'python-requests/2.18.4'} }, - 'variables': [], - 'output': ['token'] + 'variables': [] }, - 'api': {}, 'teststeps': [ { 'name': '/api/get-token', @@ -63,7 +60,7 @@ class TestHttpRunner(ApiServerUnittest): ] } ] - } + }] self.reset_all() def reset_all(self): @@ -72,46 +69,35 @@ class TestHttpRunner(ApiServerUnittest): return self.api_client.get(url, headers=headers) def test_text_run_times(self): - runner = HttpRunner().run(self.testset_path) + runner = HttpRunner().run(self.testcase_cli_path) self.assertEqual(runner.summary["stat"]["testsRun"], 10) def test_text_skip(self): - runner = HttpRunner().run(self.testset_path) + runner = HttpRunner().run(self.testcase_cli_path) self.assertEqual(runner.summary["stat"]["skipped"], 4) def test_html_report(self): - kwargs = {} - output_folder_name = os.path.basename(os.path.splitext(self.testset_path)[0]) - runner = HttpRunner().run(self.testset_path) + runner = HttpRunner().run(self.testcase_cli_path) summary = runner.summary self.assertEqual(summary["stat"]["testsRun"], 10) self.assertEqual(summary["stat"]["skipped"], 4) + output_folder_name = "demo" runner.gen_html_report(html_report_name=output_folder_name) - report_save_dir = os.path.join(loader.project_working_directory, 'reports', output_folder_name) + report_save_dir = os.path.join(os.getcwd(), 'reports', output_folder_name) self.assertGreater(len(os.listdir(report_save_dir)), 0) shutil.rmtree(report_save_dir) def test_run_testcases(self): - testcases = [self.testcase] - runner = HttpRunner().run(testcases) + runner = HttpRunner().run_tests(self.testcases) summary = runner.summary self.assertTrue(summary["success"]) self.assertEqual(summary["stat"]["testsRun"], 2) self.assertIn("details", summary) self.assertIn("records", summary["details"][0]) - def test_run_testcase(self): - testcases = self.testcase - runner = HttpRunner().run(testcases) - summary = runner.summary - self.assertTrue(summary["success"]) - self.assertEqual(summary["stat"]["testsRun"], 2) - self.assertIn("records", summary["details"][0]) - def test_run_yaml_upload(self): - testset_path = "tests/httpbin/upload.yml" - runner = HttpRunner().run(testset_path) + runner = HttpRunner().run("tests/httpbin/upload.yml") summary = runner.summary self.assertTrue(summary["success"]) self.assertEqual(summary["stat"]["testsRun"], 1) @@ -121,7 +107,14 @@ class TestHttpRunner(ApiServerUnittest): def test_run_post_data(self): testcases = [ { - "name": "post data", + "config": { + 'name': "post data", + 'request': { + 'base_url': '', + 'headers': {'User-Agent': 'python-requests/2.18.4'} + }, + 'variables': [] + }, "teststeps": [ { "name": "post data", @@ -141,25 +134,23 @@ class TestHttpRunner(ApiServerUnittest): ] } ] - runner = HttpRunner().run(testcases) + runner = HttpRunner().run_tests(testcases) summary = runner.summary self.assertTrue(summary["success"]) self.assertEqual(summary["stat"]["testsRun"], 1) self.assertEqual(summary["details"][0]["records"][0]["meta_data"]["response"]["json"]["data"], "abc") def test_html_report_repsonse_image(self): - testset_path = "tests/httpbin/load_image.yml" - runner = HttpRunner().run(testset_path) + runner = HttpRunner().run("tests/httpbin/load_image.yml") summary = runner.summary - output_folder_name = os.path.basename(os.path.splitext(testset_path)[0]) + output_folder_name = "demo" report = runner.gen_html_report(html_report_name=output_folder_name) self.assertTrue(os.path.isfile(report)) - report_save_dir = os.path.join(loader.project_working_directory, 'reports', output_folder_name) + report_save_dir = os.path.join(os.getcwd(), 'reports', output_folder_name) shutil.rmtree(report_save_dir) def test_testcase_layer(self): - testcase_path = "tests/testcases/smoketest.yml" - runner = HttpRunner(failfast=True).run(testcase_path) + runner = HttpRunner(failfast=True).run("tests/testcases/smoketest.yml") summary = runner.summary self.assertTrue(summary["success"]) self.assertEqual(summary["stat"]["testsRun"], 8) @@ -167,7 +158,6 @@ class TestHttpRunner(ApiServerUnittest): def test_run_httprunner_with_hooks(self): testcase_file_path = os.path.join( os.getcwd(), 'tests/httpbin/hooks.yml') - start_time = time.time() runner = HttpRunner().run(testcase_file_path) end_time = time.time() @@ -180,7 +170,7 @@ class TestHttpRunner(ApiServerUnittest): { "config": { "name": "test teardown hooks", - "path": "tests/httpbin/hooks.yml" + "refs": loader.load_project_tests("tests") }, "teststeps": [ { @@ -207,16 +197,15 @@ class TestHttpRunner(ApiServerUnittest): ] } ] - runner = HttpRunner().run(testcases) + runner = HttpRunner().run_tests(testcases) summary = runner.summary self.assertTrue(summary["success"]) def test_run_httprunner_with_teardown_hooks_not_exist_attribute(self): testcases = [ { - "name": "test teardown hooks", "config": { - "path": "tests/httpbin/hooks.yml" + "name": "test teardown hooks" }, "teststeps": [ { @@ -236,7 +225,7 @@ class TestHttpRunner(ApiServerUnittest): ] } ] - runner = HttpRunner().run(testcases) + runner = HttpRunner().run_tests(testcases) summary = runner.summary self.assertFalse(summary["success"]) self.assertEqual(summary["stat"]["errors"], 1) @@ -244,8 +233,9 @@ class TestHttpRunner(ApiServerUnittest): def test_run_httprunner_with_teardown_hooks_error(self): testcases = [ { - "name": "test teardown hooks", - "config": {}, + "config": { + "name": "test teardown hooks" + }, "teststeps": [ { "name": "test teardown hooks", @@ -261,7 +251,7 @@ class TestHttpRunner(ApiServerUnittest): ] } ] - runner = HttpRunner().run(testcases) + runner = HttpRunner().run_tests(testcases) summary = runner.summary self.assertFalse(summary["success"]) self.assertEqual(summary["stat"]["errors"], 1) @@ -269,30 +259,34 @@ class TestHttpRunner(ApiServerUnittest): def test_run_testcase_hardcode(self): for testcase_file_path in self.testcase_file_path_list: runner = HttpRunner().run(testcase_file_path) - self.assertTrue(runner.summary["success"]) + summary = runner.summary + self.assertTrue(summary["success"]) + self.assertEqual(summary["stat"]["testsRun"], 3) + self.assertEqual(summary["stat"]["successes"], 3) def test_run_testcases_hardcode(self): runner = HttpRunner().run(self.testcase_file_path_list) summary = runner.summary self.assertTrue(summary["success"]) + self.assertTrue(summary["success"]) self.assertEqual(summary["stat"]["testsRun"], 6) self.assertEqual(summary["stat"]["successes"], 6) - def test_run_testset_template_variables(self): + def test_run_testcase_template_variables(self): testcase_file_path = os.path.join( os.getcwd(), 'tests/data/demo_testset_variables.yml') runner = HttpRunner().run(testcase_file_path) summary = runner.summary self.assertTrue(summary["success"]) - def test_run_testset_template_import_functions(self): + def test_run_testcase_template_import_functions(self): testcase_file_path = os.path.join( os.getcwd(), 'tests/data/demo_testset_functions.yml') runner = HttpRunner().run(testcase_file_path) summary = runner.summary self.assertTrue(summary["success"]) - def test_run_testset_layered(self): + def test_run_testcase_layered(self): testcase_file_path = os.path.join( os.getcwd(), 'tests/data/demo_testset_layer.yml') runner = HttpRunner().run(testcase_file_path) @@ -347,10 +341,10 @@ class TestHttpRunner(ApiServerUnittest): def test_run_testcase_with_parameters_name(self): testcase_file_path = os.path.join( os.getcwd(), 'tests/data/demo_parameters.yml') + testcases = loader.load_tests(testcase_file_path) + parsed_testcases = api.parse_tests(testcases) runner = HttpRunner() - testcases = runner.load_tests(testcase_file_path) - parsed_testcases = runner.parse_tests(testcases) - test_suite = runner.add_tests(parsed_testcases) + test_suite = runner._add_tests(parsed_testcases) self.assertEqual( test_suite._tests[0].teststeps[0]['name'], @@ -377,28 +371,17 @@ class TestHttpRunner(ApiServerUnittest): 'get token with iOS/10.3 and test2' ) - def test_load_tests(self): + def test_validate_response_content(self): testcase_file_path = os.path.join( - os.getcwd(), 'tests/data/demo_testcase.yml') - runner = HttpRunner() - testcases = runner.load_tests(testcase_file_path) - self.assertIsInstance(testcases, list) - self.assertEqual( - testcases[0]["config"]["request"], - '$demo_default_request' - ) - self.assertEqual(testcases[0]["config"]["name"], '123$var_a') - self.assertIn( - "sum_two", - runner.project_mapping["debugtalk"]["functions"] - ) + os.getcwd(), 'tests/httpbin/basic.yml') + runner = HttpRunner().run(testcase_file_path) + self.assertTrue(runner.summary["success"]) def test_parse_tests(self): testcase_file_path = os.path.join( os.getcwd(), 'tests/data/demo_testcase.yml') - runner = HttpRunner() - testcases = runner.load_tests(testcase_file_path) - parsed_testcases = runner.parse_tests(testcases) + testcases = loader.load_tests(testcase_file_path) + parsed_testcases = api.parse_tests(testcases) self.assertEqual(parsed_testcases[0]["config"]["variables"]["var_c"], 3) self.assertEqual(len(parsed_testcases), 2 * 2) self.assertEqual( @@ -412,12 +395,6 @@ class TestHttpRunner(ApiServerUnittest): self.assertIsInstance(parsed_testcases, list) self.assertEqual(parsed_testcases[0]["config"]["name"], '12311') - def test_validate_response_content(self): - testcase_file_path = os.path.join( - os.getcwd(), 'tests/httpbin/basic.yml') - runner = HttpRunner().run(testcase_file_path) - self.assertTrue(runner.summary["success"]) - class TestLocustRunner(ApiServerUnittest): diff --git a/tests/test_context.py b/tests/test_context.py index 32da0add..72af3358 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -9,8 +9,8 @@ from tests.base import ApiServerUnittest class TestContext(ApiServerUnittest): def setUp(self): - loader.load_project_tests(os.path.join(os.getcwd(), "tests")) - self.debugtalk_module = loader.project_mapping["debugtalk"] + project_mapping = loader.load_project_tests(os.path.join(os.getcwd(), "tests")) + self.debugtalk_module = project_mapping["debugtalk"] self.context = context.Context( self.debugtalk_module["variables"], @@ -22,7 +22,6 @@ class TestContext(ApiServerUnittest): def test_init_context_functions(self): context_functions = self.context.TESTCASE_SHARED_FUNCTIONS_MAPPING self.assertIn("gen_md5", context_functions) - self.assertIn("equals", context_functions) def test_init_context_variables(self): self.assertEqual( diff --git a/tests/test_loader.py b/tests/test_loader.py index 03f8e4e0..68182c2c 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -133,29 +133,28 @@ class TestFileLoader(unittest.TestCase): self.assertEqual([], files) def test_load_dot_env_file(self): - loader.project_working_directory = os.path.join( - os.getcwd(), "tests", + dot_env_path = os.path.join( + os.getcwd(), "tests", ".env" ) - env_variables_mapping = loader.load_dot_env_file() + env_variables_mapping = loader.load_dot_env_file(dot_env_path) self.assertIn("PROJECT_KEY", env_variables_mapping) self.assertEqual(env_variables_mapping["UserName"], "debugtalk") def test_load_custom_dot_env_file(self): - loader.project_working_directory = os.path.join( - os.getcwd(), "tests", + dot_env_path = os.path.join( + os.getcwd(), "tests", "data", "test.env" ) - loader.dot_env_path = "tests/data/test.env" - env_variables_mapping = loader.load_dot_env_file() + env_variables_mapping = loader.load_dot_env_file(dot_env_path) self.assertIn("PROJECT_KEY", env_variables_mapping) self.assertEqual(env_variables_mapping["UserName"], "test") self.assertEqual(env_variables_mapping["content_type"], "application/json; charset=UTF-8") - loader.dot_env_path = None def test_load_env_path_not_exist(self): - loader.project_working_directory = os.path.join( + dot_env_path = os.path.join( os.getcwd(), "tests", "data", ) - loader.load_dot_env_file() + with self.assertRaises(exceptions.FileNotFound): + loader.load_dot_env_file(dot_env_path) def test_locate_file(self): with self.assertRaises(exceptions.FileNotFound): @@ -198,14 +197,13 @@ class TestModuleLoader(unittest.TestCase): self.assertNotIn("is_py3", functions_dict) def test_load_debugtalk_module(self): - loader.load_project_tests(os.path.join(os.getcwd(), "httprunner")) - imported_module_items = loader.project_mapping["debugtalk"] - self.assertIn("equals", imported_module_items["functions"]) + project_mapping = loader.load_project_tests(os.path.join(os.getcwd(), "httprunner")) + imported_module_items = project_mapping["debugtalk"] self.assertNotIn("SECRET_KEY", imported_module_items["variables"]) self.assertNotIn("alter_response", imported_module_items["functions"]) - loader.load_project_tests(os.path.join(os.getcwd(), "tests")) - imported_module_items = loader.project_mapping["debugtalk"] + project_mapping = loader.load_project_tests(os.path.join(os.getcwd(), "tests")) + imported_module_items = project_mapping["debugtalk"] self.assertEqual( imported_module_items["variables"]["SECRET_KEY"], "DebugTalk" @@ -229,6 +227,11 @@ class TestModuleLoader(unittest.TestCase): loader.get_module_item(module_mapping, "functions", "gen_md4") def test_get_module_item_variables(self): + dot_env_path = os.path.join( + os.getcwd(), "tests", ".env" + ) + loader.load_dot_env_file(dot_env_path) + from tests import debugtalk module_mapping = loader.load_python_module(debugtalk) @@ -258,15 +261,30 @@ class TestModuleLoader(unittest.TestCase): None ) + def test_load_tests(self): + testcase_file_path = os.path.join( + os.getcwd(), 'tests/data/demo_testcase.yml') + testcases = loader.load_tests(testcase_file_path) + self.assertIsInstance(testcases, list) + self.assertEqual( + testcases[0]["config"]["request"], + '$demo_default_request' + ) + self.assertEqual(testcases[0]["config"]["name"], '123$var_a') + self.assertIn( + "sum_two", + testcases[0]["config"]["refs"]["debugtalk"]["functions"] + ) + class TestSuiteLoader(unittest.TestCase): @classmethod def setUpClass(cls): - loader.load_project_tests(os.path.join(os.getcwd(), "tests")) + cls.project_mapping = loader.load_project_tests(os.path.join(os.getcwd(), "tests")) def test_load_test_file_testcase(self): - testcase = loader._load_test_file("tests/testcases/smoketest.yml") + testcase = loader._load_test_file("tests/testcases/smoketest.yml", self.project_mapping) self.assertEqual(testcase["config"]["name"], "smoketest") self.assertIn("device_sn", testcase["config"]["variables"][0]) self.assertEqual(len(testcase["teststeps"]), 8) @@ -274,7 +292,7 @@ class TestSuiteLoader(unittest.TestCase): def test_get_block_by_name(self): ref_call = "get_user($uid, $token)" - block = loader._get_block_by_name(ref_call, "def-api") + block = loader._get_block_by_name(ref_call, "def-api", self.project_mapping) self.assertEqual(block["request"]["url"], "/api/users/$uid") self.assertEqual(block["function_meta"]["func_name"], "get_user") self.assertEqual(block["function_meta"]["args"], ['$uid', '$token']) @@ -282,11 +300,14 @@ class TestSuiteLoader(unittest.TestCase): def test_get_block_by_name_args_mismatch(self): ref_call = "get_user($uid, $token, $var)" with self.assertRaises(exceptions.ParamsError): - loader._get_block_by_name(ref_call, "def-api") + loader._get_block_by_name(ref_call, "def-api", self.project_mapping) def test_override_block(self): def_block = loader._get_block_by_name( - "get_token($user_agent, $device_sn, $os_platform, $app_version)", "def-api") + "get_token($user_agent, $device_sn, $os_platform, $app_version)", + "def-api", + self.project_mapping + ) test_block = { "name": "override block", "variables": [ @@ -306,20 +327,20 @@ class TestSuiteLoader(unittest.TestCase): self.assertIn({'check': 'content.token', 'comparator': 'len_eq', 'expect': 32}, test_block["validate"]) def test_get_test_definition_api(self): - api_def = loader._get_test_definition("get_headers", "def-api") + api_def = loader._get_test_definition("get_headers", "def-api", self.project_mapping) self.assertEqual(api_def["request"]["url"], "/headers") self.assertEqual(len(api_def["setup_hooks"]), 2) self.assertEqual(len(api_def["teardown_hooks"]), 1) with self.assertRaises(exceptions.ApiNotFound): - loader._get_test_definition("get_token_XXX", "def-api") + loader._get_test_definition("get_token_XXX", "def-api", self.project_mapping) def test_get_test_definition_suite(self): - api_def = loader._get_test_definition("create_and_check", "def-testcase") + api_def = loader._get_test_definition("create_and_check", "def-testcase", self.project_mapping) self.assertEqual(api_def["config"]["name"], "create user and check result.") with self.assertRaises(exceptions.TestcaseNotFound): - loader._get_test_definition("create_and_check_XXX", "def-testcase") + loader._get_test_definition("create_and_check_XXX", "def-testcase", self.project_mapping) def test_merge_validator(self): def_validators = [ @@ -379,51 +400,59 @@ class TestSuiteLoader(unittest.TestCase): ) def test_load_testcases_by_path_files(self): - testsets_list = [] + testcases_list = [] # absolute file path path = os.path.join( os.getcwd(), 'tests/data/demo_testset_hardcode.json') - testset_list = loader.load_testcases(path) - self.assertEqual(len(testset_list), 1) - self.assertEqual(len(testset_list[0]["teststeps"]), 3) - testsets_list.extend(testset_list) + testcases_list = loader.load_tests(path) + self.assertEqual(len(testcases_list), 1) + self.assertEqual(len(testcases_list[0]["teststeps"]), 3) + self.assertEqual( + testcases_list[0]["config"]["refs"]["debugtalk"]["variables"]["SECRET_KEY"], + "DebugTalk" + ) + self.assertIn("get_sign", testcases_list[0]["config"]["refs"]["debugtalk"]["functions"]) # relative file path path = 'tests/data/demo_testset_hardcode.yml' - testset_list = loader.load_testcases(path) - self.assertEqual(len(testset_list), 1) - self.assertEqual(len(testset_list[0]["teststeps"]), 3) - testsets_list.extend(testset_list) + testcases_list = loader.load_tests(path) + self.assertEqual(len(testcases_list), 1) + self.assertEqual(len(testcases_list[0]["teststeps"]), 3) + self.assertEqual( + testcases_list[0]["config"]["refs"]["debugtalk"]["variables"]["SECRET_KEY"], + "DebugTalk" + ) + self.assertIn("get_sign", testcases_list[0]["config"]["refs"]["debugtalk"]["functions"]) # list/set container with file(s) path = [ os.path.join(os.getcwd(), 'tests/data/demo_testset_hardcode.json'), 'tests/data/demo_testset_hardcode.yml' ] - testset_list = loader.load_testcases(path) - self.assertEqual(len(testset_list), 2) - self.assertEqual(len(testset_list[0]["teststeps"]), 3) - self.assertEqual(len(testset_list[1]["teststeps"]), 3) - testsets_list.extend(testset_list) - self.assertEqual(len(testsets_list), 4) + testcases_list = loader.load_tests(path) + self.assertEqual(len(testcases_list), 2) + self.assertEqual(len(testcases_list[0]["teststeps"]), 3) + self.assertEqual(len(testcases_list[1]["teststeps"]), 3) + testcases_list.extend(testcases_list) + self.assertEqual(len(testcases_list), 4) - for testset in testsets_list: - for test in testset["teststeps"]: - self.assertIn('name', test) - self.assertIn('request', test) - self.assertIn('url', test['request']) - self.assertIn('method', test['request']) + for testcase in testcases_list: + for teststep in testcase["teststeps"]: + self.assertIn('name', teststep) + self.assertIn('request', teststep) + self.assertIn('url', teststep['request']) + self.assertIn('method', teststep['request']) def test_load_testcases_by_path_folder(self): # absolute folder path path = os.path.join(os.getcwd(), 'tests/data') - testset_list_1 = loader.load_testcases(path) + testset_list_1 = loader.load_tests(path) self.assertGreater(len(testset_list_1), 4) # relative folder path path = 'tests/data/' - testset_list_2 = loader.load_testcases(path) + testset_list_2 = loader.load_tests(path) self.assertEqual(len(testset_list_1), len(testset_list_2)) # list/set container with file(s) @@ -431,19 +460,19 @@ class TestSuiteLoader(unittest.TestCase): os.path.join(os.getcwd(), 'tests/data'), 'tests/data/' ] - testset_list_3 = loader.load_testcases(path) + testset_list_3 = loader.load_tests(path) self.assertEqual(len(testset_list_3), 2 * len(testset_list_1)) def test_load_testcases_by_path_not_exist(self): # absolute folder path path = os.path.join(os.getcwd(), 'tests/data_not_exist') with self.assertRaises(exceptions.FileNotFound): - loader.load_testcases(path) + loader.load_tests(path) # relative folder path path = 'tests/data_not_exist' with self.assertRaises(exceptions.FileNotFound): - loader.load_testcases(path) + loader.load_tests(path) # list/set container with file(s) path = [ @@ -451,17 +480,17 @@ class TestSuiteLoader(unittest.TestCase): 'tests/data_not_exist/' ] with self.assertRaises(exceptions.FileNotFound): - loader.load_testcases(path) + loader.load_tests(path) def test_load_testcases_by_path_layered(self): path = os.path.join( os.getcwd(), 'tests/data/demo_testset_layer.yml') - testsets_list = loader.load_testcases(path) - self.assertIn("variables", testsets_list[0]["config"]) - self.assertIn("request", testsets_list[0]["config"]) - self.assertIn("request", testsets_list[0]["teststeps"][0]) - self.assertIn("url", testsets_list[0]["teststeps"][0]["request"]) - self.assertIn("validate", testsets_list[0]["teststeps"][0]) + testcases_list = loader.load_tests(path) + self.assertIn("variables", testcases_list[0]["config"]) + self.assertIn("request", testcases_list[0]["config"]) + self.assertIn("request", testcases_list[0]["teststeps"][0]) + self.assertIn("url", testcases_list[0]["teststeps"][0]["request"]) + self.assertIn("validate", testcases_list[0]["teststeps"][0]) def test_load_folder_content(self): path = os.path.join(os.getcwd(), "tests", "api") @@ -507,8 +536,7 @@ class TestSuiteLoader(unittest.TestCase): ) def test_load_project_tests(self): - loader.load_project_tests(os.path.join(os.getcwd(), "tests")) - project_mapping = loader.project_mapping + project_mapping = loader.load_project_tests(os.path.join(os.getcwd(), "tests")) self.assertEqual(project_mapping["debugtalk"]["variables"]["SECRET_KEY"], "DebugTalk") self.assertIn("get_token", project_mapping["def-api"]) self.assertIn("setup_and_reset", project_mapping["def-testcase"]) diff --git a/tests/test_parser.py b/tests/test_parser.py index a5f0de0a..9f8c0a7c 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -384,6 +384,10 @@ class TestParser(unittest.TestCase): os.getcwd(), "tests/data/demo_parameters.yml" ) + dot_env_path = os.path.join( + os.getcwd(), "tests", ".env" + ) + loader.load_dot_env_file(dot_env_path) from tests import debugtalk debugtalk_module = loader.load_python_module(debugtalk) cartesian_product_parameters = parser.parse_parameters( @@ -412,8 +416,7 @@ class TestParser(unittest.TestCase): ) def test_parse_parameters_mix(self): - loader.load_project_tests(os.path.join(os.getcwd(), "tests")) - project_mapping = loader.project_mapping + project_mapping = loader.load_project_tests(os.path.join(os.getcwd(), "tests")) parameters = [ {"user_agent": ["iOS/10.1", "iOS/10.2", "iOS/10.3"]}, diff --git a/tests/test_runner.py b/tests/test_runner.py index ec57ee99..c4771f49 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -10,8 +10,8 @@ from tests.base import ApiServerUnittest class TestRunner(ApiServerUnittest): def setUp(self): - loader.load_project_tests(os.path.join(os.getcwd(), "tests")) - self.debugtalk_module = loader.project_mapping["debugtalk"] + project_mapping = loader.load_project_tests(os.path.join(os.getcwd(), "tests")) + self.debugtalk_module = project_mapping["debugtalk"] config_dict = { "variables": self.debugtalk_module["variables"], "functions": self.debugtalk_module["functions"] @@ -226,7 +226,7 @@ class TestRunner(ApiServerUnittest): def test_run_testcase_with_empty_header(self): testcase_file_path = os.path.join( os.getcwd(), 'tests/data/test_bugfix.yml') - testsets = loader.load_testcases(testcase_file_path) + testsets = loader.load_tests(testcase_file_path) testset = testsets[0] config_dict_headers = testset["config"]["request"]["headers"] test_dict_headers = testset["teststeps"][0]["request"]["headers"]