diff --git a/httprunner/api.py b/httprunner/api.py index fa4fe0d7..11666fed 100644 --- a/httprunner/api.py +++ b/httprunner/api.py @@ -291,7 +291,7 @@ class HttpRunner(object): logger.log_info("HttpRunner version: {}".format(__version__)) if loader.is_test_path(path_or_tests): return self.run_path(path_or_tests, dot_env_path, mapping) - elif loader.is_testcases(path_or_tests): + elif loader.is_test_content(path_or_tests): return self.run_tests(path_or_tests) else: raise exceptions.ParamsError("Invalid testcase path or testcases: {}".format(path_or_tests)) diff --git a/httprunner/loader/__init__.py b/httprunner/loader/__init__.py index c6be3e94..36f44798 100644 --- a/httprunner/loader/__init__.py +++ b/httprunner/loader/__init__.py @@ -8,14 +8,14 @@ HttpRunner loader """ -from httprunner.loader.check import is_test_path, is_testcases, JsonSchemaChecker +from httprunner.loader.check import is_test_path, is_test_content, JsonSchemaChecker from httprunner.loader.locate import get_project_working_directory as get_pwd from httprunner.loader.load import load_csv_file, load_builtin_functions from httprunner.loader.buildup import load_cases, load_project_data __all__ = [ "is_test_path", - "is_testcases", + "is_test_content", "JsonSchemaChecker", "get_pwd", "load_csv_file", diff --git a/httprunner/loader/check.py b/httprunner/loader/check.py index 61e4c052..b011be1a 100644 --- a/httprunner/loader/check.py +++ b/httprunner/loader/check.py @@ -78,103 +78,6 @@ class JsonSchemaChecker(object): return JsonSchemaChecker.validate_format(content, testsuite_schema_v2) -def is_testcase(data_structure): - """ check if data_structure is a testcase. - - Args: - data_structure (dict): testcase should always be in the following data structure: - - { - "config": { - "name": "desc1", - "variables": [], # optional - "request": {} # optional - }, - "teststeps": [ - test_dict1, - { # test_dict2 - 'name': 'test step desc2', - 'variables': [], # optional - 'extract': [], # optional - 'validate': [], - 'request': {}, - 'function_meta': {} - } - ] - } - - Returns: - bool: True if data_structure is valid testcase, otherwise False. - - """ - # TODO: replace with JSON schema validation - if not isinstance(data_structure, dict): - return False - - if "teststeps" not in data_structure: - return False - - if not isinstance(data_structure["teststeps"], list): - return False - - return True - - -def is_testcases(data_structure): - """ check if data_structure is testcase or testcases list. - - Args: - data_structure (dict): testcase(s) should always be in the following data structure: - { - "project_mapping": { - "PWD": "XXXXX", - "functions": {}, - "env": {} - }, - "testcases": [ - { # testcase data structure - "config": { - "name": "desc1", - "path": "testcase1_path", - "variables": [], # optional - }, - "teststeps": [ - # test data structure - { - 'name': 'test step desc1', - 'variables': [], # optional - 'extract': [], # optional - 'validate': [], - 'request': {} - }, - test_dict_2 # another test dict - ] - }, - testcase_dict_2 # another testcase dict - ] - } - - Returns: - bool: True if data_structure is valid testcase(s), otherwise False. - - """ - if not isinstance(data_structure, dict): - return False - - if "testcases" not in data_structure: - return False - - testcases = data_structure["testcases"] - if not isinstance(testcases, list): - return False - - for item in testcases: - if not is_testcase(item): - return False - - return True - - def is_test_path(path): """ check if path is valid json/yaml file path or a existed directory. @@ -215,3 +118,89 @@ def is_test_path(path): else: # path is neither a folder nor a file, maybe a symbol link or something else return False + + +def is_test_content(data_structure): + """ check if data_structure is apis/testcases/testsuites. + + Args: + data_structure (dict): should include keys, apis or testcases or testsuites + + Returns: + bool: True if data_structure is valid apis/testcases/testsuites, otherwise False. + + """ + if not isinstance(data_structure, dict): + return False + + if "apis" in data_structure: + # maybe a group of api content + apis = data_structure["apis"] + if not isinstance(apis, list): + return False + + for item in apis: + is_testcase = False + try: + JsonSchemaChecker.validate_api_format(item) + is_testcase = True + except exceptions.FileFormatError: + pass + + if not is_testcase: + return False + + return True + + elif "testcases" in data_structure: + # maybe a testsuite, containing a group of testcases + testcases = data_structure["testcases"] + if not isinstance(testcases, list): + return False + + for item in testcases: + is_testcase = False + try: + JsonSchemaChecker.validate_testcase_v2_format(item) + is_testcase = True + except exceptions.FileFormatError: + pass + + try: + JsonSchemaChecker.validate_testcase_v2_format(item) + is_testcase = True + except exceptions.FileFormatError: + pass + + if not is_testcase: + return False + + return True + + elif "testsuites" in data_structure: + # maybe a group of testsuites + testsuites = data_structure["testsuites"] + if not isinstance(testsuites, list): + return False + + for item in testsuites: + is_testcase = False + try: + JsonSchemaChecker.validate_testsuite_v1_format(item) + is_testcase = True + except exceptions.FileFormatError: + pass + + try: + JsonSchemaChecker.validate_testsuite_v2_format(item) + is_testcase = True + except exceptions.FileFormatError: + pass + + if not is_testcase: + return False + + return True + + else: + return False diff --git a/httprunner/loader/schemas/common.schema.json b/httprunner/loader/schemas/common.schema.json index b2e09835..0cbf6038 100644 --- a/httprunner/loader/schemas/common.schema.json +++ b/httprunner/loader/schemas/common.schema.json @@ -195,8 +195,7 @@ "description": "extraction rule for session variable, maybe in jsonpath/regex/jmespath", "type": "string" } - }, - "minProperties": 1 + } }, { "type": "array", diff --git a/tests/test_loader/test_check.py b/tests/test_loader/test_check.py index 82325a96..62de19b1 100644 --- a/tests/test_loader/test_check.py +++ b/tests/test_loader/test_check.py @@ -7,9 +7,9 @@ class TestLoaderCheck(unittest.TestCase): def test_is_testcases(self): data_structure = "path/to/file" - self.assertFalse(check.is_testcases(data_structure)) + self.assertFalse(check.is_test_content(data_structure)) data_structure = ["path/to/file1", "path/to/file2"] - self.assertFalse(check.is_testcases(data_structure)) + self.assertFalse(check.is_test_content(data_structure)) data_structure = { "project_mapping": { @@ -29,9 +29,12 @@ class TestLoaderCheck(unittest.TestCase): { 'name': 'test step desc1', 'variables': [], # optional - 'extract': [], # optional + 'extract': {}, # optional 'validate': [], - 'request': {} + 'request': { + "method": "GET", + "url": "https://docs.httprunner.org" + } }, # test_dict2 # another test dict ] @@ -39,19 +42,4 @@ class TestLoaderCheck(unittest.TestCase): # testcase_dict_2 # another testcase dict ] } - self.assertTrue(check.is_testcases(data_structure)) - data_structure = [ - { - "name": "desc1", - "config": {}, - "api": {}, - "testcases": ["testcase11", "testcase12"] - }, - { - "name": "desc2", - "config": {}, - "api": {}, - "testcases": ["testcase21", "testcase22"] - } - ] - self.assertTrue(data_structure) + self.assertTrue(check.is_test_content(data_structure))