From 3032974b736f47b0859f4ab9d4be9523d37339c6 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Wed, 27 May 2020 18:52:45 +0800 Subject: [PATCH] fix: ensure compatibility issues between testcase format v2 and v3 --- docs/CHANGELOG.md | 1 + httprunner/compat.py | 83 +++++++++++++++++++++++++++++++++ httprunner/ext/make/__init__.py | 22 +++++---- httprunner/response.py | 2 +- 4 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 httprunner/compat.py diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 97dd8cd0..caa293f7 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,7 @@ - fix: ensure converted python file in utf-8 encoding - fix: duplicate running referenced testcase +- fix: ensure compatibility issues between testcase format v2 and v3 ## 3.0.5 (2020-05-22) diff --git a/httprunner/compat.py b/httprunner/compat.py new file mode 100644 index 00000000..9101f02b --- /dev/null +++ b/httprunner/compat.py @@ -0,0 +1,83 @@ +""" +This module handles compatibility issues between testcase format v2 and v3. +""" + +from typing import List, Dict, Text + + +def convert_jmespath(raw: Text) -> Text: + if raw.startswith("content"): + return f"body{raw[len('content'):]}" + elif raw.startswith("json"): + return f"body{raw[len('json'):]}" + + return raw + + +def convert_extractors(extractors: List) -> Dict: + """ convert extract list(v2) to dict(v3) + + Args: + extractors: [{"varA": "content.varA"}, {"varB": "json.varB"}] + + Returns: + {"varA": "body.varA", "varB": "body.varB"} + + """ + if isinstance(extractors, Dict): + return extractors + + v3_extractors = {} + for extractor in extractors: + for k, v in extractor.items(): + v3_extractors[k] = convert_jmespath(v) + + return v3_extractors + + +def convert_validators(validators: List) -> List: + + for v in validators: + if "check" in v and "expect" in v: + # format1: {"check": "content.abc", "assert": "eq", "expect": 201} + v["check"] = convert_jmespath(v["check"]) + + elif len(v) == 1: + # format2: {'eq': ['status_code', 201]} + comparator = list(v.keys())[0] + v[comparator][0] = convert_jmespath(v[comparator][0]) + + return validators + + +def ensure_testcase_v3_api(api_content: Dict) -> Dict: + + return { + "config": {"name": api_content["name"]}, + "teststeps": [ + { + "name": api_content["name"], + "variables": api_content.get("variables", {}), + "request": api_content["request"], + "validate": convert_validators(api_content.get("validate", [])), + "extract": convert_extractors(api_content.get("extract", {})), + } + ], + } + + +def ensure_testcase_v3(test_content: Dict) -> Dict: + + v3_content = {"config": test_content["config"], "teststeps": []} + + for step in test_content["teststeps"]: + teststep = {} + if "api" in step: + teststep["testcase"] = step.pop("api") + + teststep["extract"] = convert_extractors(step.pop("extract", {})) + teststep["validate"] = convert_validators(step.pop("validate", [])) + teststep.update(step) + v3_content["teststeps"].append(teststep) + + return v3_content diff --git a/httprunner/ext/make/__init__.py b/httprunner/ext/make/__init__.py index ad38b65d..16a6953a 100644 --- a/httprunner/ext/make/__init__.py +++ b/httprunner/ext/make/__init__.py @@ -3,9 +3,8 @@ import subprocess from typing import Text, List, Tuple, Dict, Set, NoReturn import jinja2 -from loguru import logger - from httprunner import exceptions +from httprunner.compat import ensure_testcase_v3_api, ensure_testcase_v3 from httprunner.loader import ( load_folder_files, load_test_file, @@ -14,6 +13,7 @@ from httprunner.loader import ( load_project_meta, ) from httprunner.parser import parse_data +from loguru import logger """ cache converted pytest files, avoid duplicate making """ @@ -109,12 +109,11 @@ def __format_pytest_with_black(python_paths: List[Text]) -> NoReturn: def __make_testcase(testcase: Dict, dir_path: Text = None) -> NoReturn: """convert valid testcase dict to pytest file path""" - try: - # validate testcase format - load_testcase(testcase) - except exceptions.TestCaseFormatError as ex: - logger.error(f"TestCaseFormatError: {ex}") - raise + # ensure compatibility with testcase format v2 + testcase = ensure_testcase_v3(testcase) + + # validate testcase format + load_testcase(testcase) testcase_path = __ensure_absolute(testcase["config"]["path"]) logger.info(f"start to make testcase: {testcase_path}") @@ -255,11 +254,16 @@ def __make(tests_path: Text) -> NoReturn: 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 + # 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: diff --git a/httprunner/response.py b/httprunner/response.py index bc1f6891..022d5fe9 100644 --- a/httprunner/response.py +++ b/httprunner/response.py @@ -61,7 +61,7 @@ def uniform_validator(validator): Args: validator (dict): validator maybe in two formats: - format1: this is kept for compatiblity with the previous versions. + format1: this is kept for compatibility with the previous versions. {"check": "status_code", "assert": "eq", "expect": 201} {"check": "$resp_body_success", "assert": "eq", "expect": True} format2: recommended new version, {assert: [check_item, expected_value]}