def test_load_test_file_testcase_v2(self): for loaded_content in [ loader.load_test_file("tests/testcases/setup.v2.yml"), loader.load_test_file("tests/testcases/setup.v2.json") ]: self.assertEqual(loaded_content["type"], "testcase") self.assertIn("path", loaded_content) self.assertIn("config", loaded_content) self.assertEqual(loaded_content["config"]["name"], "setup and reset all.") self.assertIn("teststeps", loaded_content) self.assertEqual(len(loaded_content["teststeps"]), 2)
def test_load_test_file_testsuite_v2(self): for loaded_content in [ loader.load_test_file("tests/testsuites/create_users.v2.yml"), loader.load_test_file("tests/testsuites/create_users.v2.json") ]: self.assertEqual(loaded_content["type"], "testsuite") testcases = loaded_content["testcases"] self.assertEqual(len(testcases), 2) self.assertIn('create user 1000 and check result.', testcases) self.assertIn('testcase_def', testcases["create user 1000 and check result."]) self.assertEqual( testcases["create user 1000 and check result."]["testcase_def"] ["config"]["name"], "create user and check result.")
def test_create_suite(self): testcase_file_path = os.path.join( os.getcwd(), 'tests/data/demo_testset_variables.yml') testset = loader.load_test_file(testcase_file_path) suite = task.TestSuite(testset) self.assertEqual(suite.countTestCases(), 3) for testcase in suite: self.assertIsInstance(testcase, task.TestCase)
def test_load_test_file_testcase(self): loaded_content = loader.load_test_file("tests/testcases/setup.yml") self.assertEqual(loaded_content["type"], "testcase") self.assertIn("path", loaded_content) self.assertIn("config", loaded_content) self.assertEqual(loaded_content["config"]["name"], "setup and reset all.") self.assertIn("teststeps", loaded_content) self.assertEqual(len(loaded_content["teststeps"]), 2)
def test_load_test_file_testcase(self): loader.load_test_dependencies() testset = loader.load_test_file("tests/testcases/smoketest.yml") self.assertEqual(testset["config"]["name"], "smoketest") self.assertEqual(testset["config"]["path"], "tests/testcases/smoketest.yml") self.assertIn("device_sn", testset["config"]["variables"][0]) self.assertEqual(len(testset["testcases"]), 8) self.assertEqual(testset["testcases"][0]["name"], "get token")
def make_testsuite(testsuite: Dict) -> NoReturn: """convert valid testsuite dict to pytest folder with testcases""" # validate testsuite format load_testsuite(testsuite) testsuite_config = testsuite["config"] testsuite_path = testsuite_config["path"] testsuite_variables = convert_variables( testsuite_config.get("variables", {}), testsuite_path ) logger.info(f"start to make testsuite: {testsuite_path}") # create directory with testsuite file name, put its testcases under this directory testsuite_path = ensure_file_abs_path_valid(testsuite_path) testsuite_dir, file_suffix = os.path.splitext(testsuite_path) # demo_testsuite.yml => demo_testsuite_yml testsuite_dir = f"{testsuite_dir}_{file_suffix.lstrip('.')}" for testcase in testsuite["testcases"]: # get referenced testcase content testcase_file = testcase["testcase"] logger.debug(f"[make_testsuite] testcase_file={testcase_file}") testcase_path = __ensure_absolute(testcase_file) testcase_dict = load_test_file(testcase_path) testcase_dict.setdefault("config", {}) testcase_dict["config"]["path"] = testcase_path # override testcase name testcase_dict["config"]["name"] = testcase["name"] # override base_url base_url = testsuite_config.get("base_url") or testcase.get("base_url") if base_url: testcase_dict["config"]["base_url"] = base_url # override verify if "verify" in testsuite_config: testcase_dict["config"]["verify"] = testsuite_config["verify"] # override variables # testsuite testcase variables > testsuite config variables testcase_variables = convert_variables( testcase.get("variables", {}), testcase_path ) testcase_variables = merge_variables(testcase_variables, testsuite_variables) # testsuite testcase variables > testcase config variables testcase_dict["config"]["variables"] = convert_variables( testcase_dict["config"].get("variables", {}), testcase_path ) testcase_dict["config"]["variables"].update(testcase_variables) # override weight if "weight" in testcase: testcase_dict["config"]["weight"] = testcase["weight"] # make testcase testcase_pytest_path = make_testcase(testcase_dict, testsuite_dir) pytest_files_run_set.add(testcase_pytest_path)
def test_load_test_file_suite(self): loader.load_api_file("tests/api/basic.yml") testset = loader.load_test_file("tests/suite/create_and_get.yml") self.assertEqual(testset["config"]["name"], "create user and check result.") self.assertEqual(len(testset["testcases"]), 3) self.assertEqual(testset["testcases"][0]["name"], "make sure user $uid does not exist") self.assertEqual(testset["testcases"][0]["request"]["url"], "/api/users/$uid")
def make_testsuite(testsuite: Dict) -> List[Text]: """convert valid testsuite dict to pytest folder with testcases""" try: # validate testcase format load_testsuite(testsuite) except exceptions.TestSuiteFormatError as ex: logger.error(f"TestSuiteFormatError: {ex}") raise config = testsuite["config"] testsuite_path = config["path"] project_meta = load_project_meta(testsuite_path) project_working_directory = project_meta.PWD testsuite_variables = config.get("variables", {}) if isinstance(testsuite_variables, Text): # get variables by function, e.g. ${get_variables()} testsuite_variables = parse_data( testsuite_variables, {}, project_meta.functions ) logger.info(f"start to make testsuite: {testsuite_path}") # create directory with testsuite file name, put its testcases under this directory testsuite_dir = testsuite_path.replace(".", "_") os.makedirs(testsuite_dir, exist_ok=True) testcase_files = [] for testcase in testsuite["testcases"]: # get referenced testcase content testcase_file = testcase["testcase"] testcase_path = os.path.join(project_working_directory, testcase_file) testcase_dict = load_test_file(testcase_path) testcase_dict.setdefault("config", {}) testcase_dict["config"]["path"] = os.path.join( testsuite_dir, os.path.basename(testcase_path) ) # override testcase name testcase_dict["config"]["name"] = testcase["name"] # override base_url base_url = testsuite["config"].get("base_url") or testcase.get("base_url") if base_url: testcase_dict["config"]["base_url"] = base_url # override variables testcase_dict["config"].setdefault("variables", {}) testcase_dict["config"]["variables"].update(testcase.get("variables", {})) testcase_dict["config"]["variables"].update(testsuite_variables) # make testcase testcase_path = make_testcase(testcase_dict) testcase_files.append(testcase_path) return testcase_files
def __make(tests_path: Text, ref_flag: bool = False) -> NoReturn: """ make testcase(s) with testcase/testsuite/folder absolute path generated pytest file path will be cached in make_files_cache_set Args: tests_path: should be in absolute path ref_flag: flag if referenced test path """ test_files = [] if os.path.isdir(tests_path): files_list = load_folder_files(tests_path) test_files.extend(files_list) elif os.path.isfile(tests_path): test_files.append(tests_path) else: raise exceptions.TestcaseNotFound(f"Invalid tests path: {tests_path}") for test_file in test_files: if test_file.lower().endswith("_test.py"): pytest_files_set.add(test_file) continue try: test_content = load_test_file(test_file) except (exceptions.FileNotFound, exceptions.FileFormatError) as ex: logger.warning(ex) continue # api in v2 format, convert to v3 testcase if "request" in test_content: test_content = ensure_testcase_v3_api(test_content) test_content.setdefault("config", {})["path"] = test_file # testcase if "teststeps" in test_content: try: make_testcase(test_content, ref_flag=ref_flag) except exceptions.TestCaseFormatError: continue # testsuite elif "testcases" in test_content: try: make_testsuite(test_content) except exceptions.TestSuiteFormatError: continue # invalid format else: logger.warning( f"skip invalid testcase/testsuite file: {test_file}")
def __make(tests_path: Text) -> NoReturn: """ make testcase(s) with testcase/testsuite/folder absolute path generated pytest file path will be cached in make_files_cache_set Args: tests_path: should be in absolute path """ test_files = [] if os.path.isdir(tests_path): files_list = load_folder_files(tests_path) test_files.extend(files_list) elif os.path.isfile(tests_path): test_files.append(tests_path) else: raise exceptions.TestcaseNotFound(f"Invalid tests path: {tests_path}") for test_file in test_files: try: test_content = load_test_file(test_file) except (exceptions.FileNotFound, exceptions.FileFormatError) as ex: logger.warning(ex) continue # api in v2 format, convert to v3 testcase if "request" in test_content: test_content = ensure_testcase_v3_api(test_content) test_content.setdefault("config", {})["path"] = test_file # testcase if "teststeps" in test_content: try: __make_testcase(test_content) except exceptions.TestCaseFormatError: continue # testsuite elif "testcases" in test_content: try: __make_testsuite(test_content) except exceptions.TestSuiteFormatError: continue # invalid format else: raise exceptions.FileFormatError( f"test file is neither testcase nor testsuite: {test_file}")
def __make(tests_path: Text) -> List: test_files = [] if os.path.isdir(tests_path): files_list = load_folder_files(tests_path) test_files.extend(files_list) elif os.path.isfile(tests_path): test_files.append(tests_path) else: raise exceptions.TestcaseNotFound(f"Invalid tests path: {tests_path}") testcase_path_list = [] for test_file in test_files: try: test_content = load_test_file(test_file) test_content.setdefault("config", {})["path"] = test_file except (exceptions.FileNotFound, exceptions.FileFormatError) as ex: logger.warning(ex) continue # testcase if "teststeps" in test_content: try: testcase_file = make_testcase(test_content) except exceptions.TestCaseFormatError: continue testcase_path_list.append(testcase_file) # testsuite elif "testcases" in test_content: try: testcase_files = make_testsuite(test_content) except exceptions.TestSuiteFormatError: continue testcase_path_list.extend(testcase_files) # invalid format else: raise exceptions.FileFormatError( f"test file is neither testcase nor testsuite: {test_file}" ) if not testcase_path_list: logger.warning(f"No valid testcase generated on {tests_path}") return [] return testcase_path_list
def __make_testsuite(testsuite: Dict) -> NoReturn: """convert valid testsuite dict to pytest folder with testcases""" # validate testsuite format load_testsuite(testsuite) config = testsuite["config"] testsuite_path = config["path"] testsuite_variables = 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) logger.info(f"start to make testsuite: {testsuite_path}") # create directory with testsuite file name, put its testcases under this directory testsuite_dir = os.path.join( os.path.dirname(testsuite_path), os.path.basename(testsuite_path).replace(".", "_"), ) os.makedirs(testsuite_dir, exist_ok=True) for testcase in testsuite["testcases"]: # get referenced testcase content testcase_file = testcase["testcase"] testcase_path = __ensure_absolute(testcase_file) testcase_dict = load_test_file(testcase_path) testcase_dict.setdefault("config", {}) testcase_dict["config"]["path"] = testcase_path # override testcase name testcase_dict["config"]["name"] = testcase["name"] # override base_url base_url = testsuite["config"].get("base_url") or testcase.get( "base_url") if base_url: testcase_dict["config"]["base_url"] = base_url # override variables testcase_dict["config"].setdefault("variables", {}) testcase_dict["config"]["variables"].update( testcase.get("variables", {})) testcase_dict["config"]["variables"].update(testsuite_variables) # make testcase __make_testcase(testcase_dict, testsuite_dir)
def gen_locustfile(testcase_file_path): """ generate locustfile from template. """ locustfile_path = 'locustfile.py' template_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), "templates", "locustfile_template" ) loader.load_test_dependencies() testset = loader.load_test_file(testcase_file_path) host = testset.get("config", {}).get("request", {}).get("base_url", "") with io.open(template_path, encoding='utf-8') as template: with io.open(locustfile_path, 'w', encoding='utf-8') as locustfile: template_content = template.read() template_content = template_content.replace("$HOST", host) template_content = template_content.replace("$TESTCASE_FILE", testcase_file_path) locustfile.write(template_content) return locustfile_path
def __make(tests_path: Text) -> NoReturn: """ make testcase(s) with testcase/testsuite/folder absolute path generated pytest file path will be cached in pytest_files_made_cache_mapping Args: tests_path: should be in absolute path """ logger.info(f"make path: {tests_path}") test_files = [] if os.path.isdir(tests_path): files_list = load_folder_files(tests_path) test_files.extend(files_list) elif os.path.isfile(tests_path): test_files.append(tests_path) else: raise exceptions.TestcaseNotFound(f"Invalid tests path: {tests_path}") for test_file in test_files: if test_file.lower().endswith("_test.py"): pytest_files_run_set.add(test_file) continue try: test_content = load_test_file(test_file) except (exceptions.FileNotFound, exceptions.FileFormatError) as ex: logger.warning( f"Invalid test file: {test_file}\n{type(ex).__name__}: {ex}") continue if not isinstance(test_content, Dict): logger.warning(f"Invalid test file: {test_file}\n" f"reason: test content not in dict format.") continue # api in v2 format, convert to v3 testcase if "request" in test_content and "name" in test_content: test_content = ensure_testcase_v3_api(test_content) if "config" not in test_content: logger.warning(f"Invalid testcase/testsuite file: {test_file}\n" f"reason: missing config part.") continue elif not isinstance(test_content["config"], Dict): logger.warning( f"Invalid testcase/testsuite file: {test_file}\n" f"reason: config should be dict type, got {test_content['config']}" ) continue # ensure path absolute test_content.setdefault("config", {})["path"] = test_file # testcase if "teststeps" in test_content: try: testcase_pytest_path = make_testcase(test_content) pytest_files_run_set.add(testcase_pytest_path) except exceptions.TestCaseFormatError as ex: logger.warning( f"Invalid testcase file: {test_file}\n{type(ex).__name__}: {ex}" ) continue # testsuite elif "testcases" in test_content: try: make_testsuite(test_content) except exceptions.TestSuiteFormatError as ex: logger.warning( f"Invalid testsuite file: {test_file}\n{type(ex).__name__}: {ex}" ) continue # invalid format else: logger.warning( f"Invalid test file: {test_file}\n" f"reason: file content is neither testcase nor testsuite")
def make_testcase(testcase: Dict, dir_path: Text = None) -> Text: """convert valid testcase dict to pytest file path""" # ensure compatibility with testcase format v2 testcase = ensure_testcase_v3(testcase) # validate testcase format load_testcase(testcase) testcase_abs_path = __ensure_absolute(testcase["config"]["path"]) logger.info(f"start to make testcase: {testcase_abs_path}") testcase_python_abs_path, testcase_cls_name = convert_testcase_path( testcase_abs_path) if dir_path: testcase_python_abs_path = os.path.join( dir_path, os.path.basename(testcase_python_abs_path)) global pytest_files_made_cache_mapping if testcase_python_abs_path in pytest_files_made_cache_mapping: return testcase_python_abs_path config = testcase["config"] config["path"] = convert_relative_project_root_dir( testcase_python_abs_path) config["variables"] = convert_variables(config.get("variables", {}), testcase_abs_path) # prepare reference testcase imports_list = [] teststeps = testcase["teststeps"] for teststep in teststeps: if not teststep.get("testcase"): continue # make ref testcase pytest file ref_testcase_path = __ensure_absolute(teststep["testcase"]) test_content = load_test_file(ref_testcase_path) # api in v2 format, convert to v3 testcase if "request" in test_content and "name" in test_content: test_content = ensure_testcase_v3_api(test_content) test_content.setdefault("config", {})["path"] = ref_testcase_path ref_testcase_python_abs_path = make_testcase(test_content) # override testcase export ref_testcase_export: List = test_content["config"].get("export", []) if ref_testcase_export: step_export: List = teststep.setdefault("export", []) step_export.extend(ref_testcase_export) teststep["export"] = list(set(step_export)) # prepare ref testcase class name ref_testcase_cls_name = pytest_files_made_cache_mapping[ ref_testcase_python_abs_path] teststep["testcase"] = ref_testcase_cls_name # prepare import ref testcase ref_testcase_python_relative_path = convert_relative_project_root_dir( ref_testcase_python_abs_path) ref_module_name, _ = os.path.splitext( ref_testcase_python_relative_path) ref_module_name = ref_module_name.replace(os.sep, ".") import_expr = f"from {ref_module_name} import TestCase{ref_testcase_cls_name} as {ref_testcase_cls_name}" if import_expr not in imports_list: imports_list.append(import_expr) testcase_path = convert_relative_project_root_dir(testcase_abs_path) # current file compared to ProjectRootDir diff_levels = len(testcase_path.split(os.sep)) data = { "version": __version__, "testcase_path": testcase_path, "diff_levels": diff_levels, "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), "teststeps_chain_style": [make_teststep_chain_style(step) for step in teststeps], } content = __TEMPLATE__.render(data) # ensure new file's directory exists dir_path = os.path.dirname(testcase_python_abs_path) if not os.path.exists(dir_path): os.makedirs(dir_path) with open(testcase_python_abs_path, "w", encoding="utf-8") as f: f.write(content) pytest_files_made_cache_mapping[ testcase_python_abs_path] = testcase_cls_name __ensure_testcase_module(testcase_python_abs_path) logger.info(f"generated testcase: {testcase_python_abs_path}") return testcase_python_abs_path
def test_load_test_file_api(self): loaded_content = loader.load_test_file("tests/api/create_user.yml") self.assertEqual(loaded_content["type"], "api") self.assertIn("path", loaded_content) self.assertIn("request", loaded_content) self.assertEqual(loaded_content["request"]["url"], "/api/users/$uid")
def make_testcase(testcase: Dict, dir_path: Text = None) -> Text: """convert valid testcase dict to pytest file path""" # ensure compatibility with testcase format v2 testcase = ensure_testcase_v3(testcase) # validate testcase format load_testcase(testcase) testcase_abs_path = __ensure_absolute(testcase["config"]["path"]) logger.info(f"start to make testcase: {testcase_abs_path}") testcase_python_path, testcase_cls_name = convert_testcase_path( testcase_abs_path) if dir_path: testcase_python_path = os.path.join( dir_path, os.path.basename(testcase_python_path)) global pytest_files_made_cache_mapping if testcase_python_path in pytest_files_made_cache_mapping: return testcase_python_path config = testcase["config"] config["path"] = __ensure_cwd_relative(testcase_python_path) config["variables"] = convert_variables(config.get("variables", {}), testcase_abs_path) # prepare reference testcase imports_list = [] teststeps = testcase["teststeps"] for teststep in teststeps: if not teststep.get("testcase"): continue # make ref testcase pytest file ref_testcase_path = __ensure_absolute(teststep["testcase"]) test_content = load_test_file(ref_testcase_path) test_content.setdefault("config", {})["path"] = ref_testcase_path ref_testcase_python_path = make_testcase(test_content) # prepare ref testcase class name ref_testcase_cls_name = pytest_files_made_cache_mapping[ ref_testcase_python_path] teststep["testcase"] = ref_testcase_cls_name # prepare import ref testcase ref_testcase_python_path = ref_testcase_python_path[len(os.getcwd()) + 1:] ref_module_name, _ = os.path.splitext(ref_testcase_python_path) ref_module_name = ref_module_name.replace(os.sep, ".") imports_list.append( f"from {ref_module_name} import TestCase{ref_testcase_cls_name} as {ref_testcase_cls_name}" ) data = { "version": __version__, "testcase_path": __ensure_cwd_relative(testcase_abs_path), "class_name": f"TestCase{testcase_cls_name}", "imports_list": imports_list, "config_chain_style": make_config_chain_style(config), "teststeps_chain_style": [make_teststep_chain_style(step) for step in teststeps], } content = __TEMPLATE__.render(data) # ensure new file's directory exists dir_path = os.path.dirname(testcase_python_path) if not os.path.exists(dir_path): os.makedirs(dir_path) with open(testcase_python_path, "w", encoding="utf-8") as f: f.write(content) pytest_files_made_cache_mapping[testcase_python_path] = testcase_cls_name __ensure_testcase_module(testcase_python_path) logger.info(f"generated testcase: {testcase_python_path}") return testcase_python_path