1. 程式人生 > 其它 >httprunner原始碼學習(三)__make()

httprunner原始碼學習(三)__make()

mian_make()方法的第12行執行此方法;
打眼一看有點複雜,作者註釋的意思大概是使用絕對路徑建立testcase,生成pytest檔案並快取;
還是來逐行看吧。

  • 31行之前都是對目錄/檔案的處理(.json .yaml .py)
  • 40行讀取了 .json .yaml 檔案內容,開始進行處理(提取、排序等)
  • 42-53行是對異常情況的處理(config不存在、config沒有name欄位、config不是字典等)
  • 第59行開始就是httprunner的核心之一了,用例生成
  • 第61行呼叫了自定義方法:make_testcase,我們去下面會研究一下這個方法
# httprunner/make.py :: __make
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)  # 自定義方法,作用是返回這個目錄下所有以.yml/.yaml/.json/_test.py結尾的檔案,返回值是個list。這個遞迴演算法也很有嚼頭,建議食用。
        test_files.extend(files_list)  # 將返回的list存入 test_files
    elif os.path.isfile(tests_path):  # 如果不是目錄
        test_files.append(tests_path)  # 直接存入 test_files
    else:
        raise exceptions.TestcaseNotFound(f"Invalid tests path: {tests_path}")

    for test_file in test_files:
        if test_file.lower().endswith("_test.py"):  # 如果檔名小寫後以_test.py結尾
            pytest_files_run_set.add(test_file)  # pytest_files_run_set 是定義在 make.py 的一個全域性變數,set型別。
            continue

        try:
            test_content = load_test_file(test_file)  # 自定義方法,作用是根據字尾判斷檔案型別(yaml/json),並返回讀取之後的內容(dict)
        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):  # 如果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:  # 如果request 和 name 在讀好的json/yaml檔案的第一層,執行ensure_testcase_v3_api方法
            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  # 給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"
            )