mirror of
https://github.com/httprunner/httprunner.git
synced 2026-08-28 19:47:14 +08:00
refactor: move validate testcase code from validator to loader
This commit is contained in:
+1
-1
@@ -5,11 +5,11 @@ import sys
|
|||||||
from httprunner import __description__, __version__
|
from httprunner import __description__, __version__
|
||||||
from httprunner.api import HttpRunner
|
from httprunner.api import HttpRunner
|
||||||
from httprunner.compat import is_py2
|
from httprunner.compat import is_py2
|
||||||
|
from httprunner.loader import validate_json_file
|
||||||
from httprunner.logger import color_print
|
from httprunner.logger import color_print
|
||||||
from httprunner.report import gen_html_report
|
from httprunner.report import gen_html_report
|
||||||
from httprunner.utils import (create_scaffold, get_python2_retire_msg,
|
from httprunner.utils import (create_scaffold, get_python2_retire_msg,
|
||||||
prettify_json_file)
|
prettify_json_file)
|
||||||
from httprunner.validator import validate_json_file
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
+171
-2
@@ -4,6 +4,7 @@ import io
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import types
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
@@ -17,6 +18,149 @@ except AttributeError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: validate data format with JSON schema
|
||||||
|
|
||||||
|
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_testcase_path(path):
|
||||||
|
""" check if path is testcase path or path list.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (str/list): file path or file path list.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if path is valid file path or path list, otherwise False.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not isinstance(path, (str, list)):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if isinstance(path, list):
|
||||||
|
for p in path:
|
||||||
|
if not is_testcase_path(p):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if isinstance(path, str):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def validate_json_file(file_list):
|
||||||
|
""" validate JSON testcase format
|
||||||
|
"""
|
||||||
|
for json_file in set(file_list):
|
||||||
|
if not json_file.endswith(".json"):
|
||||||
|
logger.log_warning("Only JSON file format can be validated, skip: {}".format(json_file))
|
||||||
|
continue
|
||||||
|
|
||||||
|
logger.color_print("Start to validate JSON file: {}".format(json_file), "GREEN")
|
||||||
|
|
||||||
|
with io.open(json_file) as stream:
|
||||||
|
try:
|
||||||
|
json.load(stream)
|
||||||
|
except ValueError as e:
|
||||||
|
raise SystemExit(e)
|
||||||
|
|
||||||
|
print("OK")
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# file loader
|
# file loader
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -244,6 +388,31 @@ def locate_file(start_path, file_name):
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def is_function(item):
|
||||||
|
""" Takes item object, returns True if it is a function.
|
||||||
|
"""
|
||||||
|
return isinstance(item, types.FunctionType)
|
||||||
|
|
||||||
|
|
||||||
|
def is_variable(tup):
|
||||||
|
""" Takes (name, object) tuple, returns True if it is a variable.
|
||||||
|
"""
|
||||||
|
name, item = tup
|
||||||
|
if callable(item):
|
||||||
|
# function or class
|
||||||
|
return False
|
||||||
|
|
||||||
|
if isinstance(item, types.ModuleType):
|
||||||
|
# imported module
|
||||||
|
return False
|
||||||
|
|
||||||
|
if name.startswith("_"):
|
||||||
|
# private property
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def load_module_functions(module):
|
def load_module_functions(module):
|
||||||
""" load python module functions.
|
""" load python module functions.
|
||||||
|
|
||||||
@@ -262,7 +431,7 @@ def load_module_functions(module):
|
|||||||
module_functions = {}
|
module_functions = {}
|
||||||
|
|
||||||
for name, item in vars(module).items():
|
for name, item in vars(module).items():
|
||||||
if validator.is_function(item):
|
if is_function(item):
|
||||||
module_functions[name] = item
|
module_functions[name] = item
|
||||||
|
|
||||||
return module_functions
|
return module_functions
|
||||||
@@ -724,7 +893,7 @@ def load_api_folder(api_folder_path):
|
|||||||
for api_item in api_items:
|
for api_item in api_items:
|
||||||
key, api_dict = api_item.popitem()
|
key, api_dict = api_item.popitem()
|
||||||
api_id = api_dict.get("id") or api_dict.get("def") \
|
api_id = api_dict.get("id") or api_dict.get("def") \
|
||||||
or api_dict.get("name")
|
or api_dict.get("name")
|
||||||
if key != "api" or not api_id:
|
if key != "api" or not api_id:
|
||||||
raise exceptions.ParamsError(
|
raise exceptions.ParamsError(
|
||||||
"Invalid API defined in {}".format(api_file_path))
|
"Invalid API defined in {}".format(api_file_path))
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
import collections
|
import collections
|
||||||
import io
|
|
||||||
import json
|
import json
|
||||||
import types
|
|
||||||
|
|
||||||
from httprunner import exceptions, logger, parser
|
from httprunner import exceptions, logger, parser
|
||||||
|
|
||||||
@@ -171,55 +169,6 @@ def extend_validators(raw_validators, override_validators):
|
|||||||
return list(def_validators_mapping.values())
|
return list(def_validators_mapping.values())
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
## validate varibles and functions
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
|
|
||||||
def is_function(item):
|
|
||||||
""" Takes item object, returns True if it is a function.
|
|
||||||
"""
|
|
||||||
return isinstance(item, types.FunctionType)
|
|
||||||
|
|
||||||
|
|
||||||
def is_variable(tup):
|
|
||||||
""" Takes (name, object) tuple, returns True if it is a variable.
|
|
||||||
"""
|
|
||||||
name, item = tup
|
|
||||||
if callable(item):
|
|
||||||
# function or class
|
|
||||||
return False
|
|
||||||
|
|
||||||
if isinstance(item, types.ModuleType):
|
|
||||||
# imported module
|
|
||||||
return False
|
|
||||||
|
|
||||||
if name.startswith("_"):
|
|
||||||
# private property
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def validate_json_file(file_list):
|
|
||||||
""" validate JSON testcase format
|
|
||||||
"""
|
|
||||||
for json_file in set(file_list):
|
|
||||||
if not json_file.endswith(".json"):
|
|
||||||
logger.log_warning("Only JSON file format can be validated, skip: {}".format(json_file))
|
|
||||||
continue
|
|
||||||
|
|
||||||
logger.color_print("Start to validate JSON file: {}".format(json_file), "GREEN")
|
|
||||||
|
|
||||||
with io.open(json_file) as stream:
|
|
||||||
try:
|
|
||||||
json.load(stream)
|
|
||||||
except ValueError as e:
|
|
||||||
raise SystemExit(e)
|
|
||||||
|
|
||||||
print("OK")
|
|
||||||
|
|
||||||
|
|
||||||
class Validator(object):
|
class Validator(object):
|
||||||
"""Validate tests
|
"""Validate tests
|
||||||
|
|
||||||
|
|||||||
@@ -476,3 +476,73 @@ class TestSuiteLoader(unittest.TestCase):
|
|||||||
api_file_path = os.path.join(os.getcwd(), "tests", "api", "get_token.yml")
|
api_file_path = os.path.join(os.getcwd(), "tests", "api", "get_token.yml")
|
||||||
self.assertIn(api_file_path, self.tests_def_mapping["api"])
|
self.assertIn(api_file_path, self.tests_def_mapping["api"])
|
||||||
self.assertEqual(self.project_mapping["env"]["PROJECT_KEY"], "ABCDEFGH")
|
self.assertEqual(self.project_mapping["env"]["PROJECT_KEY"], "ABCDEFGH")
|
||||||
|
|
||||||
|
def test_is_function(self):
|
||||||
|
func = lambda x: x + 1
|
||||||
|
self.assertTrue(loader.is_function(func))
|
||||||
|
self.assertTrue(loader.is_function(loader.is_testcase))
|
||||||
|
|
||||||
|
def test_is_testcases(self):
|
||||||
|
data_structure = "path/to/file"
|
||||||
|
self.assertFalse(loader.is_testcases(data_structure))
|
||||||
|
data_structure = ["path/to/file1", "path/to/file2"]
|
||||||
|
self.assertFalse(loader.is_testcases(data_structure))
|
||||||
|
|
||||||
|
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_dict2 # another test dict
|
||||||
|
]
|
||||||
|
},
|
||||||
|
# testcase_dict_2 # another testcase dict
|
||||||
|
]
|
||||||
|
}
|
||||||
|
self.assertTrue(loader.is_testcases(data_structure))
|
||||||
|
data_structure = [
|
||||||
|
{
|
||||||
|
"name": "desc1",
|
||||||
|
"config": {},
|
||||||
|
"api": {},
|
||||||
|
"testcases": ["testcase11", "testcase12"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "desc2",
|
||||||
|
"config": {},
|
||||||
|
"api": {},
|
||||||
|
"testcases": ["testcase21", "testcase22"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
self.assertTrue(data_structure)
|
||||||
|
|
||||||
|
def test_is_variable(self):
|
||||||
|
var1 = 123
|
||||||
|
var2 = "abc"
|
||||||
|
self.assertTrue(loader.is_variable(("var1", var1)))
|
||||||
|
self.assertTrue(loader.is_variable(("var2", var2)))
|
||||||
|
|
||||||
|
__var = 123
|
||||||
|
self.assertFalse(loader.is_variable(("__var", __var)))
|
||||||
|
|
||||||
|
func = lambda x: x + 1
|
||||||
|
self.assertFalse(loader.is_variable(("func", func)))
|
||||||
|
|
||||||
|
self.assertFalse(loader.is_variable(("unittest", unittest)))
|
||||||
|
|||||||
@@ -5,76 +5,6 @@ from httprunner import validator
|
|||||||
|
|
||||||
class TestValidator(unittest.TestCase):
|
class TestValidator(unittest.TestCase):
|
||||||
|
|
||||||
def test_is_testcases(self):
|
|
||||||
data_structure = "path/to/file"
|
|
||||||
self.assertFalse(validator.is_testcases(data_structure))
|
|
||||||
data_structure = ["path/to/file1", "path/to/file2"]
|
|
||||||
self.assertFalse(validator.is_testcases(data_structure))
|
|
||||||
|
|
||||||
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_dict2 # another test dict
|
|
||||||
]
|
|
||||||
},
|
|
||||||
# testcase_dict_2 # another testcase dict
|
|
||||||
]
|
|
||||||
}
|
|
||||||
self.assertTrue(validator.is_testcases(data_structure))
|
|
||||||
data_structure = [
|
|
||||||
{
|
|
||||||
"name": "desc1",
|
|
||||||
"config": {},
|
|
||||||
"api": {},
|
|
||||||
"testcases": ["testcase11", "testcase12"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "desc2",
|
|
||||||
"config": {},
|
|
||||||
"api": {},
|
|
||||||
"testcases": ["testcase21", "testcase22"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
self.assertTrue(data_structure)
|
|
||||||
|
|
||||||
def test_is_variable(self):
|
|
||||||
var1 = 123
|
|
||||||
var2 = "abc"
|
|
||||||
self.assertTrue(validator.is_variable(("var1", var1)))
|
|
||||||
self.assertTrue(validator.is_variable(("var2", var2)))
|
|
||||||
|
|
||||||
__var = 123
|
|
||||||
self.assertFalse(validator.is_variable(("__var", __var)))
|
|
||||||
|
|
||||||
func = lambda x: x + 1
|
|
||||||
self.assertFalse(validator.is_variable(("func", func)))
|
|
||||||
|
|
||||||
self.assertFalse(validator.is_variable(("unittest", unittest)))
|
|
||||||
|
|
||||||
def test_is_function(self):
|
|
||||||
func = lambda x: x + 1
|
|
||||||
self.assertTrue(validator.is_function(func))
|
|
||||||
self.assertTrue(validator.is_function(validator.is_testcase))
|
|
||||||
|
|
||||||
def test_get_uniform_comparator(self):
|
def test_get_uniform_comparator(self):
|
||||||
self.assertEqual(validator.get_uniform_comparator("eq"), "equals")
|
self.assertEqual(validator.get_uniform_comparator("eq"), "equals")
|
||||||
self.assertEqual(validator.get_uniform_comparator("=="), "equals")
|
self.assertEqual(validator.get_uniform_comparator("=="), "equals")
|
||||||
|
|||||||
Reference in New Issue
Block a user