def test_ensure_file_path_valid(self): self.assertEqual( ensure_file_path_valid("examples/a-b.c/d f/hardcode.yml"), os.path.join(os.getcwd(), "examples/a_b_c/d_f/hardcode.yml"), ) self.assertEqual( ensure_file_path_valid("1/2B/3.yml"), os.path.join(os.getcwd(), "T1/T2B/T3.yml"), ) self.assertEqual( ensure_file_path_valid("examples/a-b.c/2B/hardcode.yml"), os.path.join(os.getcwd(), "examples/a_b_c/T2B/hardcode.yml"), ) self.assertEqual( ensure_file_path_valid("examples/postman_echo/request_methods/"), os.path.join(os.getcwd(), "examples/postman_echo/request_methods"), )
def test_ensure_file_path_valid(self): self.assertEqual( ensure_file_path_valid( os.path.join("examples", "a-b.c", "d f", "hardcode.yml")), os.path.join(os.getcwd(), "examples", "a_b_c", "d_f", "hardcode.yml"), ) self.assertEqual( ensure_file_path_valid(os.path.join("1", "2B", "3.yml")), os.path.join(os.getcwd(), "T1", "T2B", "T3.yml"), ) self.assertEqual( ensure_file_path_valid( os.path.join("examples", "a-b.c", "2B", "hardcode.yml")), os.path.join(os.getcwd(), "examples", "a_b_c", "T2B", "hardcode.yml"), ) self.assertEqual( ensure_file_path_valid( os.path.join("examples", "postman_echo", "request_methods")), os.path.join(os.getcwd(), "examples", "postman_echo", "request_methods"), ) self.assertEqual( ensure_file_path_valid(os.path.join(os.getcwd(), "test.yml")), os.path.join(os.getcwd(), "test.yml"), ) self.assertEqual( ensure_file_path_valid(os.getcwd()), os.getcwd(), ) self.assertEqual( ensure_file_path_valid(os.path.join(os.getcwd(), "demo", ".csv")), os.path.join(os.getcwd(), "demo", ".csv"), )
def convert_testcase_path(testcase_path: Text) -> Tuple[Text, Text]: """convert single YAML/JSON testcase path to python file""" testcase_new_path = ensure_file_path_valid(testcase_path) dir_path = os.path.dirname(testcase_new_path) file_name, _ = os.path.splitext(os.path.basename(testcase_new_path)) testcase_python_path = os.path.join(dir_path, f"{file_name}_test.py") # convert title case, e.g. request_with_variables => RequestWithVariables name_in_title_case = file_name.title().replace("_", "") return testcase_python_path, name_in_title_case
def __ensure_project_meta_files(tests_path: Text) -> NoReturn: """ ensure project meta files exist in generated pytest folder files include debugtalk.py and .env """ project_meta = load_project_meta(tests_path) # handle cases when generated pytest directory are different from original yaml/json testcases debugtalk_path = project_meta.debugtalk_path if debugtalk_path: debugtalk_new_path = ensure_file_path_valid(debugtalk_path) if debugtalk_new_path != debugtalk_path: logger.info(f"copy debugtalk.py to {debugtalk_new_path}") copyfile(debugtalk_path, debugtalk_new_path) global pytest_files_made_cache_mapping pytest_files_made_cache_mapping[debugtalk_new_path] = "" dot_csv_path = project_meta.dot_env_path if dot_csv_path: dot_csv_new_path = ensure_file_path_valid(dot_csv_path) if dot_csv_new_path != dot_csv_path: logger.info(f"copy .env to {dot_csv_new_path}") copyfile(dot_csv_path, dot_csv_new_path)
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_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"] 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 = override_config_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) # make testcase testcase_pytest_path = make_testcase(testcase_dict, testsuite_dir) pytest_files_run_set.add(testcase_pytest_path)
def generate_conftest_for_summary(args: List): for arg in args: if os.path.exists(arg): test_path = arg # FIXME: several test paths maybe specified break else: logger.error(f"No valid test path specified! \nargs: {args}") sys.exit(1) project_meta = load_project_meta(test_path) project_root_dir = ensure_file_path_valid(project_meta.RootDir) conftest_path = os.path.join(project_root_dir, "conftest.py") conftest_content = '''# NOTICE: Generated By HttpRunner. import json import os import time import pytest from loguru import logger from httprunner.utils import get_platform, ExtendJSONEncoder @pytest.fixture(scope="session", autouse=True) def session_fixture(request): """setup and teardown each task""" logger.info(f"start running testcases ...") start_at = time.time() yield logger.info(f"task finished, generate task summary for --save-tests") summary = { "success": True, "stat": { "testcases": {"total": 0, "success": 0, "fail": 0}, "teststeps": {"total": 0, "failures": 0, "successes": 0}, }, "time": {"start_at": start_at, "duration": time.time() - start_at}, "platform": get_platform(), "details": [], } for item in request.node.items: testcase_summary = item.instance.get_summary() summary["success"] &= testcase_summary.success summary["stat"]["testcases"]["total"] += 1 summary["stat"]["teststeps"]["total"] += len(testcase_summary.step_datas) if testcase_summary.success: summary["stat"]["testcases"]["success"] += 1 summary["stat"]["teststeps"]["successes"] += len( testcase_summary.step_datas ) else: summary["stat"]["testcases"]["fail"] += 1 summary["stat"]["teststeps"]["successes"] += ( len(testcase_summary.step_datas) - 1 ) summary["stat"]["teststeps"]["failures"] += 1 testcase_summary_json = testcase_summary.dict() testcase_summary_json["records"] = testcase_summary_json.pop("step_datas") summary["details"].append(testcase_summary_json) summary_path = "{{SUMMARY_PATH_PLACEHOLDER}}" summary_dir = os.path.dirname(summary_path) os.makedirs(summary_dir, exist_ok=True) with open(summary_path, "w", encoding="utf-8") as f: json.dump(summary, f, indent=4, ensure_ascii=False, cls=ExtendJSONEncoder) logger.info(f"generated task summary: {summary_path}") ''' test_path = os.path.abspath(test_path) logs_dir_path = os.path.join(project_root_dir, "logs") test_path_relative_path = test_path[len(project_root_dir) + 1:] if os.path.isdir(test_path): file_foder_path = os.path.join(logs_dir_path, test_path_relative_path) dump_file_name = "all.summary.json" else: file_relative_folder_path, test_file = os.path.split( test_path_relative_path) file_foder_path = os.path.join(logs_dir_path, file_relative_folder_path) test_file_name, _ = os.path.splitext(test_file) dump_file_name = f"{test_file_name}.summary.json" summary_path = os.path.join(file_foder_path, dump_file_name) conftest_content = conftest_content.replace("{{SUMMARY_PATH_PLACEHOLDER}}", summary_path) dir_path = os.path.dirname(conftest_path) if not os.path.exists(dir_path): os.makedirs(dir_path) with open(conftest_path, "w", encoding="utf-8") as f: f.write(conftest_content) logger.info("generated conftest.py to generate summary.json")