feat: implement lazy parser for validators

This commit is contained in:
debugtalk
2019-04-08 12:12:09 +08:00
parent 0e663d19cb
commit 3d1c7f368c
15 changed files with 760 additions and 704 deletions

View File

@@ -74,11 +74,9 @@ class HttpRunner(object):
return test
test_suite = unittest.TestSuite()
functions = tests_mapping.get("project_mapping", {}).get("functions", {})
for testcase in tests_mapping["testcases"]:
config = testcase.get("config", {})
test_runner = runner.Runner(config, functions)
test_runner = runner.Runner(config)
TestSequense = type('TestSequense', (unittest.TestCase,), {})
tests = testcase.get("teststeps", [])

View File

@@ -8,8 +8,9 @@ def main_hrun():
from httprunner.__about__ import __description__, __version__
from httprunner.api import HttpRunner
from httprunner.compat import is_py2
from httprunner.validator import validate_json_file
from httprunner.utils import (create_scaffold, get_python2_retire_msg,
prettify_json_file, validate_json_file)
prettify_json_file)
parser = argparse.ArgumentParser(description=__description__)
parser.add_argument(

View File

@@ -5,18 +5,16 @@ class SessionContext(object):
""" HttpRunner session, store runtime variables.
Examples:
>>> functions={...}
>>> variables = {"SECRET_KEY": "DebugTalk"}
>>> context = SessionContext(functions, variables)
>>> context = SessionContext(variables)
Equivalent to:
>>> context = SessionContext(functions)
>>> context = SessionContext()
>>> context.update_session_variables(variables)
"""
def __init__(self, functions, variables=None):
def __init__(self, variables=None):
self.session_variables_mapping = utils.ensure_mapping_format(variables or {})
self.FUNCTIONS_MAPPING = functions
self.init_test_variables()
self.validation_results = []
@@ -63,32 +61,20 @@ class SessionContext(object):
"""
return parser.parse_lazy_data(content, self.test_variables_mapping)
def __eval_check_item(self, validator, resp_obj):
def __eval_validator_check(self, check_item, resp_obj):
""" evaluate check item in validator.
Args:
validator (dict): validator
{"check": "status_code", "comparator": "eq", "expect": 201}
{"check": "$resp_body_success", "comparator": "eq", "expect": True}
resp_obj (object): requests.Response() object
check_item: check_item should only be the following 5 formats:
1, variable reference, e.g. $token
2, function reference, e.g. ${is_status_code_200($status_code)}
3, dict or list, maybe containing variable/function reference, e.g. {"var": "$abc"}
4, string joined by delimiter. e.g. "status_code", "headers.content-type"
5, regex string, e.g. "LB[\d]*(.*)RB[\d]*"
Returns:
dict: validator info
{
"check": "status_code",
"check_value": 200,
"expect": 201,
"comparator": "eq"
}
resp_obj: response object
"""
check_item = validator["check"]
# check_item should only be the following 5 formats:
# 1, variable reference, e.g. $token
# 2, function reference, e.g. ${is_status_code_200($status_code)}
# 3, dict or list, maybe containing variable/function reference, e.g. {"var": "$abc"}
# 4, string joined by delimiter. e.g. "status_code", "headers.content-type"
# 5, regex string, e.g. "LB[\d]*(.*)RB[\d]*"
if isinstance(check_item, (dict, list)) \
or isinstance(check_item, parser.LazyString):
# format 1/2/3
@@ -97,68 +83,22 @@ class SessionContext(object):
# format 4/5
check_value = resp_obj.extract_field(check_item)
validator["check_value"] = check_value
return check_value
# expect_value should only be in 2 types:
# 1, variable reference, e.g. $expect_status_code
# 2, actual value, e.g. 200
expect_value = self.eval_content(validator["expect"])
validator["expect"] = expect_value
validator["check_result"] = "unchecked"
return validator
def _do_validation(self, validator_dict):
""" validate with functions
def __eval_validator_expect(self, expect_item):
""" evaluate expect item in validator.
Args:
validator_dict (dict): validator dict
{
"check": "status_code",
"check_value": 200,
"expect": 201,
"comparator": "eq"
}
expect_item: expect_item should only be in 2 types:
1, variable reference, e.g. $expect_status_code
2, actual value, e.g. 200
"""
# TODO: move comparator uniform to init_test_suites
comparator = utils.get_uniform_comparator(validator_dict["comparator"])
validate_func = parser.get_mapping_function(comparator, self.FUNCTIONS_MAPPING)
check_item = validator_dict["check"]
check_value = validator_dict["check_value"]
expect_value = validator_dict["expect"]
if (check_value is None or expect_value is None) \
and comparator not in ["is", "eq", "equals", "=="]:
raise exceptions.ParamsError("Null value can only be compared with comparator: eq/equals/==")
validate_msg = "validate: {} {} {}({})".format(
check_item,
comparator,
expect_value,
type(expect_value).__name__
)
try:
validator_dict["check_result"] = "pass"
validate_func(check_value, expect_value)
validate_msg += "\t==> pass"
logger.log_debug(validate_msg)
except (AssertionError, TypeError):
validate_msg += "\t==> fail"
validate_msg += "\n{}({}) {} {}({})".format(
check_value,
type(check_value).__name__,
comparator,
expect_value,
type(expect_value).__name__
)
logger.log_error(validate_msg)
validator_dict["check_result"] = "fail"
raise exceptions.ValidationFailure(validate_msg)
expect_value = self.eval_content(expect_item)
return expect_value
def validate(self, validators, resp_obj):
""" make validations
""" make validation with comparators
"""
self.validation_results = []
if not validators:
@@ -170,19 +110,59 @@ class SessionContext(object):
failures = []
for validator in validators:
# evaluate validators with context variable mapping.
evaluated_validator = self.__eval_check_item(
parser.parse_validator(validator),
# validator should be LazyFunction object
if not isinstance(validator, parser.LazyFunction):
raise exceptions.ValidationFailure(
"validator should be parsed first: {}".format(validators))
# evaluate validator args with context variable mapping.
validator_args = validator._args
check_item, expect_item = validator_args
check_value = self.__eval_validator_check(
check_item,
resp_obj
)
expect_value = self.__eval_validator_expect(expect_item)
validator._args = [check_value, expect_value]
comparator = validator._func.__name__
validator_dict = {
"comparator": comparator,
"check": check_item,
"check_value": check_value,
"expect": expect_item,
"expect_value": expect_value
}
validate_msg = "\nvalidate: {} {} {}({})".format(
check_item,
comparator,
expect_value,
type(expect_value).__name__
)
try:
self._do_validation(evaluated_validator)
except exceptions.ValidationFailure as ex:
validator.to_value(self.test_variables_mapping)
validator_dict["check_result"] = "pass"
validate_msg += "\t==> pass"
logger.log_debug(validate_msg)
except (AssertionError, TypeError):
validate_pass = False
failures.append(str(ex))
validator_dict["check_result"] = "fail"
validate_msg += "\t==> fail"
validate_msg += "\n{}({}) {} {}({})".format(
check_value,
type(check_value).__name__,
comparator,
expect_value,
type(expect_value).__name__
)
logger.log_error(validate_msg)
failures.append(validate_msg)
self.validation_results.append(evaluated_validator)
self.validation_results.append(validator_dict)
# restore validator args, in case of running multiple times
validator._args = validator_args
if not validate_pass:
failures_string = "\n".join([failure for failure in failures])

View File

@@ -4,7 +4,7 @@ import ast
import os
import re
from httprunner import exceptions, utils
from httprunner import exceptions, utils, validator
from httprunner.compat import basestring, builtin_str, numeric_types, str
# TODO: change variable notation from $var to {{var}}
@@ -105,65 +105,6 @@ def regex_findall_functions(content):
return []
def parse_validator(validator):
""" parse validator
Args:
validator (dict): validator maybe in two formats:
format1: this is kept for compatiblity with the previous versions.
{"check": "status_code", "comparator": "eq", "expect": 201}
{"check": "$resp_body_success", "comparator": "eq", "expect": True}
format2: recommended new version
{'eq': ['status_code', 201]}
{'eq': ['$resp_body_success', True]}
Returns
dict: validator info
{
"check": "status_code",
"expect": 201,
"comparator": "eq"
}
"""
if not isinstance(validator, dict):
raise exceptions.ParamsError("invalid validator: {}".format(validator))
if "check" in validator and len(validator) > 1:
# format1
check_item = validator.get("check")
if "expect" in validator:
expect_value = validator.get("expect")
elif "expected" in validator:
expect_value = validator.get("expected")
else:
raise exceptions.ParamsError("invalid validator: {}".format(validator))
comparator = validator.get("comparator", "eq")
elif len(validator) == 1:
# format2
comparator = list(validator.keys())[0]
compare_values = validator[comparator]
if not isinstance(compare_values, list) or len(compare_values) != 2:
raise exceptions.ParamsError("invalid validator: {}".format(validator))
check_item, expect_value = compare_values
else:
raise exceptions.ParamsError("invalid validator: {}".format(validator))
return {
"check": check_item,
"expect": expect_value,
"comparator": comparator
}
def parse_parameters(parameters, variables_mapping=None, functions_mapping=None):
""" parse parameters and generate cartesian product.
@@ -738,12 +679,9 @@ def _extend_with_api(test_dict, api_def_dict):
""" extend test with api definition, test will merge and override api definition.
Args:
test_dict (dict): test block
test_dict (dict): test block, this will override api_def_dict
api_def_dict (dict): api definition
Returns:
dict: extended test dict.
Examples:
>>> api_def_dict = {
"name": "get token 1",
@@ -756,6 +694,7 @@ def _extend_with_api(test_dict, api_def_dict):
"validate": [{'eq': ['status_code', 201]}, {'len_eq': ['content.token', 16]}]
}
>>> _extend_with_api(test_dict, api_def_dict)
>>> print(test_dict)
{
"name": "get token 2",
"request": {...},
@@ -764,9 +703,8 @@ def _extend_with_api(test_dict, api_def_dict):
}
"""
# override name
api_def_name = api_def_dict.pop("name", "")
test_dict["name"] = test_dict.get("name") or api_def_name
# override api name
test_dict.setdefault("name", api_def_dict.pop("name", ""))
# override variables
def_variables = api_def_dict.pop("variables", [])
@@ -777,16 +715,12 @@ def _extend_with_api(test_dict, api_def_dict):
# merge & override validators TODO: relocate
def_raw_validators = api_def_dict.pop("validate", [])
ref_raw_validators = test_dict.get("validate", [])
def_validators = [
parse_validator(validator)
for validator in def_raw_validators
validator.uniform_validator(_validator)
for _validator in def_raw_validators
]
ref_validators = [
parse_validator(validator)
for validator in ref_raw_validators
]
test_dict["validate"] = utils.extend_validators(
ref_validators = test_dict.pop("validate", [])
test_dict["validate"] = validator.extend_validators(
def_validators,
ref_validators
)
@@ -798,7 +732,7 @@ def _extend_with_api(test_dict, api_def_dict):
test_dict.get("extract", {})
)
# TODO: merge & override request
# merge & override request
test_dict["request"] = api_def_dict.pop("request", {})
# base_url & verify: priority api_def_dict > test_dict
@@ -824,8 +758,6 @@ def _extend_with_api(test_dict, api_def_dict):
# TODO: extend with other api definition items, e.g. times
test_dict.update(api_def_dict)
return test_dict
def _extend_with_testcase(test_dict, testcase_def_dict):
""" extend test with testcase definition
@@ -923,6 +855,14 @@ def __prepare_testcase_tests(tests, config, project_mapping):
if (not test_dict.get("base_url")) and config_base_url:
test_dict["base_url"] = config_base_url
# unify validators' format
if "validate" in test_dict:
ref_raw_validators = test_dict.pop("validate", [])
test_dict["validate"] = [
validator.uniform_validator(_validator)
for _validator in ref_raw_validators
]
if "testcase_def" in test_dict:
# test_dict is nested testcase
@@ -954,6 +894,27 @@ def __prepare_testcase_tests(tests, config, project_mapping):
check_variables_set = set(test_dict_variables.keys()) \
| set(session_variables.keys()) | {"request", "response"}
# convert validators to lazy function
validators = test_dict.pop("validate", [])
prepared_validators = []
for _validator in validators:
function_meta = {
"func_name": _validator["comparator"],
"args": [
_validator["check"],
_validator["expect"]
],
"kwargs": {}
}
prepared_validators.append(
LazyFunction(
function_meta,
functions,
check_variables_set
)
)
test_dict["validate"] = prepared_validators
# convert variables and functions to lazy object.
# raises VariableNotFound if undefined variable exists in test_dict
prepared_test_dict = prepare_lazy_data(

View File

@@ -11,27 +11,40 @@ class Runner(object):
""" Running testcases.
Examples:
>>> functions={...}
>>> config = {
"name": "XXXX",
"base_url": "http://127.0.0.1",
"verify": False
>>> tests_mapping = {
"project_mapping": {
"functions": {}
},
"testcases": [
{
"config": {
"name": "XXXX",
"base_url": "http://127.0.0.1",
"verify": False
},
"teststeps": [
{
"name": "test description",
"variables": [], # optional
"request": {
"url": "http://127.0.0.1:5000/api/users/1000",
"method": "GET"
}
}
]
}
]
}
>>> runner = Runner(config, functions)
>>> test_dict = {
"name": "test description",
"variables": [], # optional
"request": {
"url": "http://127.0.0.1:5000/api/users/1000",
"method": "GET"
}
}
>>> runner.run_test(test_dict)
>>> parsed_tests_mapping = parser.parse_tests(tests_mapping)
>>> parsed_testcase = parsed_tests_mapping["testcases"][0]
>>> test_runner = runner.Runner(parsed_testcase["config"])
>>> test_runner.run_test(parsed_testcase["teststeps"][0])
"""
def __init__(self, config, functions, http_client_session=None):
def __init__(self, config, http_client_session=None):
""" run testcase or testsuite.
Args:
@@ -50,7 +63,6 @@ class Runner(object):
base_url = config.get("base_url")
self.verify = config.get("verify", True)
self.output = config.get("output", [])
self.functions = functions
self.validation_results = []
# testcase setup hooks
@@ -59,7 +71,7 @@ class Runner(object):
self.testcase_teardown_hooks = config.get("teardown_hooks", [])
self.http_client_session = http_client_session or HttpSession(base_url)
self.session_context = SessionContext(self.functions)
self.session_context = SessionContext()
if testcase_setup_hooks:
self.do_hook_actions(testcase_setup_hooks, "setup")
@@ -289,7 +301,7 @@ class Runner(object):
config = testcase_dict.get("config", {})
# each teststeps in one testcase (YAML/JSON) share the same session.
test_runner = Runner(config, self.functions, self.http_client_session)
test_runner = Runner(config, self.http_client_session)
tests = testcase_dict.get("teststeps", [])

View File

@@ -15,7 +15,7 @@ logging.getLogger('locust.runners').setLevel(logging.INFO)
class WebPageTasks(TaskSet):
def on_start(self):
self.test_runner = Runner(self.locust.config, self.locust.functions, self.client)
self.test_runner = Runner(self.locust.config, self.client)
@task
def test_any(self):
@@ -38,7 +38,6 @@ class WebPageUser(HttpLocust):
file_path = "$TESTCASE_FILE"
locust_tests = prepare_locust_tests(file_path)
functions = locust_tests["functions"]
tests = locust_tests["tests"]
config = {}

View File

@@ -120,39 +120,6 @@ def query_json(json_content, query, delimiter='.'):
return json_content
def get_uniform_comparator(comparator):
""" convert comparator alias to uniform name
"""
if comparator in ["eq", "equals", "==", "is"]:
return "equals"
elif comparator in ["lt", "less_than"]:
return "less_than"
elif comparator in ["le", "less_than_or_equals"]:
return "less_than_or_equals"
elif comparator in ["gt", "greater_than"]:
return "greater_than"
elif comparator in ["ge", "greater_than_or_equals"]:
return "greater_than_or_equals"
elif comparator in ["ne", "not_equals"]:
return "not_equals"
elif comparator in ["str_eq", "string_equals"]:
return "string_equals"
elif comparator in ["len_eq", "length_equals", "count_eq"]:
return "length_equals"
elif comparator in ["len_gt", "count_gt", "length_greater_than", "count_greater_than"]:
return "length_greater_than"
elif comparator in ["len_ge", "count_ge", "length_greater_than_or_equals", \
"count_greater_than_or_equals"]:
return "length_greater_than_or_equals"
elif comparator in ["len_lt", "count_lt", "length_less_than", "count_less_than"]:
return "length_less_than"
elif comparator in ["len_le", "count_le", "length_less_than_or_equals", \
"count_less_than_or_equals"]:
return "length_less_than_or_equals"
else:
return comparator
def deep_update_dict(origin_dict, override_dict):
""" update origin dict with override dict recursively
e.g. origin_dict = {'a': 1, 'b': {'c': 2, 'd': 4}}
@@ -323,78 +290,6 @@ def ensure_mapping_format(variables):
raise exceptions.ParamsError("variables format error!")
def _convert_validators_to_mapping(validators):
""" convert validators list to mapping.
Args:
validators (list): validators in list
Returns:
dict: validators mapping, use (check, comparator) as key.
Examples:
>>> validators = [
{"check": "v1", "expect": 201, "comparator": "eq"},
{"check": {"b": 1}, "expect": 200, "comparator": "eq"}
]
>>> _convert_validators_to_mapping(validators)
{
("v1", "eq"): {"check": "v1", "expect": 201, "comparator": "eq"},
('{"b": 1}', "eq"): {"check": {"b": 1}, "expect": 200, "comparator": "eq"}
}
"""
validators_mapping = {}
for validator in validators:
if not isinstance(validator["check"], collections.Hashable):
check = json.dumps(validator["check"])
else:
check = validator["check"]
key = (check, validator["comparator"])
validators_mapping[key] = validator
return validators_mapping
def extend_validators(raw_validators, override_validators):
""" extend raw_validators with override_validators.
override_validators will merge and override raw_validators.
Args:
raw_validators (dict):
override_validators (dict):
Returns:
list: extended validators
Examples:
>>> raw_validators = [{'eq': ['v1', 200]}, {"check": "s2", "expect": 16, "comparator": "len_eq"}]
>>> override_validators = [{"check": "v1", "expect": 201}, {'len_eq': ['s3', 12]}]
>>> extend_validators(raw_validators, override_validators)
[
{"check": "v1", "expect": 201, "comparator": "eq"},
{"check": "s2", "expect": 16, "comparator": "len_eq"},
{"check": "s3", "expect": 12, "comparator": "len_eq"}
]
"""
if not raw_validators:
return override_validators
elif not override_validators:
return raw_validators
else:
def_validators_mapping = _convert_validators_to_mapping(raw_validators)
ref_validators_mapping = _convert_validators_to_mapping(override_validators)
def_validators_mapping.update(ref_validators_mapping)
return list(def_validators_mapping.values())
def extend_variables(raw_variables, override_variables):
""" extend raw_variables with override_variables.
override_variables will merge and override raw_variables.
@@ -581,25 +476,6 @@ def gen_cartesian_product(*args):
return product_list
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")
def prettify_json_file(file_list):
""" prettify JSON testcase format
"""

View File

@@ -1,7 +1,12 @@
# encoding: utf-8
import collections
import io
import json
import os
import types
from httprunner import exceptions, logger
""" validate data format
TODO: refactor with JSON schema validate
@@ -129,6 +134,170 @@ def is_testcase_path(path):
return True
###############################################################################
## testcase validator utils
###############################################################################
def get_uniform_comparator(comparator):
""" convert comparator alias to uniform name
"""
if comparator in ["eq", "equals", "==", "is"]:
return "equals"
elif comparator in ["lt", "less_than"]:
return "less_than"
elif comparator in ["le", "less_than_or_equals"]:
return "less_than_or_equals"
elif comparator in ["gt", "greater_than"]:
return "greater_than"
elif comparator in ["ge", "greater_than_or_equals"]:
return "greater_than_or_equals"
elif comparator in ["ne", "not_equals"]:
return "not_equals"
elif comparator in ["str_eq", "string_equals"]:
return "string_equals"
elif comparator in ["len_eq", "length_equals", "count_eq"]:
return "length_equals"
elif comparator in ["len_gt", "count_gt", "length_greater_than", "count_greater_than"]:
return "length_greater_than"
elif comparator in ["len_ge", "count_ge", "length_greater_than_or_equals", \
"count_greater_than_or_equals"]:
return "length_greater_than_or_equals"
elif comparator in ["len_lt", "count_lt", "length_less_than", "count_less_than"]:
return "length_less_than"
elif comparator in ["len_le", "count_le", "length_less_than_or_equals", \
"count_less_than_or_equals"]:
return "length_less_than_or_equals"
else:
return comparator
def uniform_validator(validator):
""" unify validator
Args:
validator (dict): validator maybe in two formats:
format1: this is kept for compatiblity with the previous versions.
{"check": "status_code", "comparator": "eq", "expect": 201}
{"check": "$resp_body_success", "comparator": "eq", "expect": True}
format2: recommended new version, {comparator: [check_item, expected_value]}
{'eq': ['status_code', 201]}
{'eq': ['$resp_body_success', True]}
Returns
dict: validator info
{
"check": "status_code",
"expect": 201,
"comparator": "equals"
}
"""
if not isinstance(validator, dict):
raise exceptions.ParamsError("invalid validator: {}".format(validator))
if "check" in validator and "expect" in validator:
# format1
check_item = validator["check"]
expect_value = validator["expect"]
comparator = validator.get("comparator", "eq")
elif len(validator) == 1:
# format2
comparator = list(validator.keys())[0]
compare_values = validator[comparator]
if not isinstance(compare_values, list) or len(compare_values) != 2:
raise exceptions.ParamsError("invalid validator: {}".format(validator))
check_item, expect_value = compare_values
else:
raise exceptions.ParamsError("invalid validator: {}".format(validator))
# uniform comparator, e.g. lt => less_than, eq => equals
comparator = get_uniform_comparator(comparator)
return {
"check": check_item,
"expect": expect_value,
"comparator": comparator
}
def _convert_validators_to_mapping(validators):
""" convert validators list to mapping.
Args:
validators (list): validators in list
Returns:
dict: validators mapping, use (check, comparator) as key.
Examples:
>>> validators = [
{"check": "v1", "expect": 201, "comparator": "eq"},
{"check": {"b": 1}, "expect": 200, "comparator": "eq"}
]
>>> _convert_validators_to_mapping(validators)
{
("v1", "eq"): {"check": "v1", "expect": 201, "comparator": "eq"},
('{"b": 1}', "eq"): {"check": {"b": 1}, "expect": 200, "comparator": "eq"}
}
"""
validators_mapping = {}
for validator in validators:
if not isinstance(validator["check"], collections.Hashable):
check = json.dumps(validator["check"])
else:
check = validator["check"]
key = (check, validator["comparator"])
validators_mapping[key] = validator
return validators_mapping
def extend_validators(raw_validators, override_validators):
""" extend raw_validators with override_validators.
override_validators will merge and override raw_validators.
Args:
raw_validators (dict):
override_validators (dict):
Returns:
list: extended validators
Examples:
>>> raw_validators = [{'eq': ['v1', 200]}, {"check": "s2", "expect": 16, "comparator": "len_eq"}]
>>> override_validators = [{"check": "v1", "expect": 201}, {'len_eq': ['s3', 12]}]
>>> extend_validators(raw_validators, override_validators)
[
{"check": "v1", "expect": 201, "comparator": "eq"},
{"check": "s2", "expect": 16, "comparator": "len_eq"},
{"check": "s3", "expect": 12, "comparator": "len_eq"}
]
"""
if not raw_validators:
return override_validators
elif not override_validators:
return raw_validators
else:
def_validators_mapping = _convert_validators_to_mapping(raw_validators)
ref_validators_mapping = _convert_validators_to_mapping(override_validators)
def_validators_mapping.update(ref_validators_mapping)
return list(def_validators_mapping.values())
###############################################################################
## validate varibles and functions
###############################################################################
@@ -157,3 +326,22 @@ def is_variable(tup):
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")

View File

@@ -6,5 +6,6 @@ request:
url: https://debugtalk.com
status_code: 302
method: GET
verify: False
validate:
- eq: ["status_code", 200]

View File

@@ -76,7 +76,7 @@ class TestHttpClient(ApiServerUnittest):
"a": "1",
"b": "2"
}
resp = self.api_client.get(url, cookies=cookies, headers=self.headers)
resp = self.api_client.get(url, cookies=cookies, headers=self.headers, verify=False)
raw_request = resp.history[0].request
self.assertEqual(raw_request._cookies["a"], "1")
self.assertEqual(raw_request._cookies["b"], "2")

View File

@@ -1,8 +1,7 @@
import os
import time
import requests
from httprunner import context, exceptions, loader, parser, response, utils
from httprunner import context, exceptions, loader, parser, runner
from tests.base import ApiServerUnittest, gen_md5, gen_random_string
@@ -11,16 +10,10 @@ class TestContext(ApiServerUnittest):
def setUp(self):
loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
project_mapping = loader.project_mapping
self.functions = project_mapping["functions"]
self.context = context.SessionContext(
functions=self.functions,
variables={"SECRET_KEY": "DebugTalk"}
)
def test_init_context_functions(self):
context_functions = self.context.FUNCTIONS_MAPPING
self.assertIn("gen_md5", context_functions)
def test_init_test_variables_initialize(self):
self.assertEqual(
self.context.test_variables_mapping,
@@ -57,13 +50,6 @@ class TestContext(ApiServerUnittest):
"debugtalk"
)
def test_eval_content_functions(self):
content = parser.prepare_lazy_data("${sleep_N_secs(1)}", self.functions)
start_time = time.time()
self.context.eval_content(content)
elapsed_time = time.time() - start_time
self.assertGreater(elapsed_time, 1)
def test_eval_content_variables(self):
variables = {
"SECRET_KEY": "DebugTalk"
@@ -124,82 +110,80 @@ class TestContext(ApiServerUnittest):
)
self.assertEqual(parsed_request["headers"]["secret_key"], "DebugTalk")
def test_do_validation(self):
self.context._do_validation(
{"check": "check", "check_value": 1, "expect": 1, "comparator": "eq"}
)
self.context._do_validation(
{"check": "check", "check_value": "abc", "expect": "abc", "comparator": "=="}
)
self.context._do_validation(
{"check": "status_code", "check_value": "201", "expect": 3, "comparator": "sum_status_code"}
)
def test_validate(self):
url = "http://127.0.0.1:5000/"
resp = requests.get(url)
resp_obj = response.ResponseObject(resp)
validators = [
{"eq": ["$resp_status_code", 201]},
{"check": "$resp_status_code", "comparator": "eq", "expect": 201},
{"check": "$resp_body_success", "comparator": "eq", "expect": True}
]
validators = parser.prepare_lazy_data(validators, {}, {"resp_status_code", "resp_body_success"})
variables = {
"resp_status_code": 200,
"resp_body_success": True
}
self.context.init_test_variables(variables)
with self.assertRaises(exceptions.ValidationFailure):
self.context.validate(validators, resp_obj)
validators = [
{"eq": ["$resp_status_code", 201]},
{"check": "$resp_status_code", "comparator": "eq", "expect": 201},
{"check": "$resp_body_success", "comparator": "eq", "expect": True},
{"check": "${is_status_code_200($resp_status_code)}", "comparator": "eq", "expect": False}
testcases = [
{
"config": {
'name': "test validation"
},
"teststeps": [
{
"name": "test validation",
"request": {
"url": "http://127.0.0.1:5000/",
"method": "GET",
},
"variables": {
"resp_status_code": 200,
"resp_body_success": True
},
"validate": [
{"eq": ["$resp_status_code", 200]},
{"check": "$resp_status_code", "comparator": "eq", "expect": 200},
{"check": "$resp_body_success", "expect": True},
{"check": "${is_status_code_200($resp_status_code)}", "expect": True}
]
}
]
}
]
from tests.debugtalk import is_status_code_200
functions = {
"is_status_code_200": is_status_code_200
tests_mapping = {
"project_mapping": {
"functions": {
"is_status_code_200": is_status_code_200
}
},
"testcases": testcases
}
validators = parser.prepare_lazy_data(
validators, functions, {"resp_status_code", "resp_body_success"})
variables = [
{"resp_status_code": 201},
{"resp_body_success": True}
]
self.context.init_test_variables(variables)
self.context.validate(validators, resp_obj)
self.context.validate([], resp_obj)
self.assertEqual(self.context.validation_results, [])
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
teststep = parsed_testcase["teststeps"][0]
test_runner.run_test(teststep)
def test_validate_exception(self):
url = "http://127.0.0.1:5000/"
resp = requests.get(url)
resp_obj = response.ResponseObject(resp)
# expected value missed in validators
validators = [
{"eq": ["$resp_status_code", 201]},
{"check": "$resp_status_code", "comparator": "eq", "expect": 201}
testcases = [
{
"config": {
'name': "test validation"
},
"teststeps": [
{
"name": "test validation",
"request": {
"url": "http://127.0.0.1:5000/",
"method": "GET",
},
"variables": {
"resp_status_code": 200,
"resp_body_success": True
},
"validate": [
{"eq": ["$resp_status_code", 201]},
{"check": "$resp_status_code", "expect": 201},
{"check": "$resp_body_success", "comparator": "eq", "expect": True}
]
}
]
}
]
validators = parser.prepare_lazy_data(validators, {}, {"resp_status_code"})
variables = []
self.context.init_test_variables(variables)
with self.assertRaises(exceptions.VariableNotFound):
self.context.validate(validators, resp_obj)
# expected value missed in variables mapping
variables = [
{"resp_status_code": 200}
]
self.context.init_test_variables(variables)
tests_mapping = {
"testcases": testcases
}
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
teststep = parsed_testcase["teststeps"][0]
with self.assertRaises(exceptions.ValidationFailure):
self.context.validate(validators, resp_obj)
test_runner.run_test(teststep)

View File

@@ -104,19 +104,6 @@ class TestParserBasic(unittest.TestCase):
{'args': ["$request", '12 3'], 'kwargs': {}}
)
def test_parse_validator(self):
validator = {"check": "status_code", "comparator": "eq", "expect": 201}
self.assertEqual(
parser.parse_validator(validator),
{"check": "status_code", "comparator": "eq", "expect": 201}
)
validator = {'eq': ['status_code', 201]}
self.assertEqual(
parser.parse_validator(validator),
{"check": "status_code", "comparator": "eq", "expect": 201}
)
def test_extract_variables(self):
prepared_content = parser.prepare_lazy_data("123$a", {}, {"a"})
self.assertEqual(
@@ -1076,15 +1063,15 @@ class TestParser(unittest.TestCase):
'json': {'sign': '${get_sign($device_sn, $os_platform, $app_version)}'}
},
'validate': [
{'eq': ['status_code', 201]},
{'len_eq': ['content.token', 32]}
{"check": "status_code", "comparator": "equals", "expect": 201},
{"check": "content.token", "comparator": "length_equals", "expect": 32}
]
}
extended_block = parser._extend_with_api(test_block, api_def_dict)
self.assertEqual(extended_block["base_url"], "https://debugtalk.com")
self.assertEqual(extended_block["name"], "override block")
self.assertEqual({'var': 123}, extended_block["variables"])
self.assertIn({'check': 'status_code', 'expect': 201, 'comparator': 'eq'}, extended_block["validate"])
self.assertIn({'check': 'content.token', 'comparator': 'len_eq', 'expect': 32}, extended_block["validate"])
self.assertEqual(extended_block["times"], 3)
parser._extend_with_api(test_block, api_def_dict)
self.assertEqual(test_block["base_url"], "https://debugtalk.com")
self.assertEqual(test_block["name"], "override block")
self.assertEqual({'var': 123}, test_block["variables"])
self.assertIn({'check': 'status_code', 'expect': 201, 'comparator': 'equals'}, test_block["validate"])
self.assertIn({'check': 'content.token', 'comparator': 'length_equals', 'expect': 32}, test_block["validate"])
self.assertEqual(test_block["times"], 3)

View File

@@ -1,8 +1,7 @@
import os
import time
from httprunner import exceptions, loader, parser, runner
from httprunner.utils import deep_update_dict
from httprunner import loader, parser, runner
from tests.api_server import HTTPBIN_SERVER
from tests.base import ApiServerUnittest
@@ -19,7 +18,7 @@ class TestRunner(ApiServerUnittest):
"base_url": "http://127.0.0.1",
"verify": False
}
self.test_runner = runner.Runner(config, self.debugtalk_functions)
self.test_runner = runner.Runner(config)
self.reset_all()
def reset_all(self):
@@ -36,214 +35,253 @@ class TestRunner(ApiServerUnittest):
]
for testcase_file_path in testcase_file_path_list:
testcases = loader.load_file(testcase_file_path)
testcases = parser.prepare_lazy_data(
testcases,
self.debugtalk_functions,
{"expect_status_code", "token_len", "token", "success"}
)
config_dict = {}
test_runner = runner.Runner(config_dict, self.debugtalk_functions)
test = testcases[0]["test"]
test_runner.run_test(test)
test = testcases[1]["test"]
test_runner.run_test(test)
test = testcases[2]["test"]
test_runner.run_test(test)
def test_run_single_testcase_fail(self):
test = {
"name": "get token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3",
"device_sn": "HZfFBh6tU59EdXJ",
"os_platform": "ios",
"app_version": "2.8.6"
},
"json": {
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
},
"validate": [
{"check": "status_code", "expect": 205},
{"check": "content.token", "comparator": "len_eq", "expect": 19}
]
}
with self.assertRaises(exceptions.ValidationFailure):
self.test_runner.run_test(test)
tests_mapping = loader.load_tests(testcase_file_path)
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
test_runner.run_test(parsed_testcase["teststeps"][0])
test_runner.run_test(parsed_testcase["teststeps"][1])
test_runner.run_test(parsed_testcase["teststeps"][2])
def test_run_testcase_with_hooks(self):
start_time = time.time()
config_dict = {
"name": "basic test with httpbin",
"base_url": HTTPBIN_SERVER,
"setup_hooks": [
"${sleep_N_secs(0.5)}",
"${hook_print(setup)}"
],
"teardown_hooks": [
"${sleep_N_secs(1)}",
"${hook_print(teardown)}"
]
testcases = [
{
"config": {
"name": "basic test with httpbin",
"base_url": HTTPBIN_SERVER,
"setup_hooks": [
"${sleep_N_secs(0.5)}",
"${hook_print(setup)}"
],
"teardown_hooks": [
"${sleep_N_secs(1)}",
"${hook_print(teardown)}"
]
},
"teststeps": [
{
"name": "get token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3",
"device_sn": "HZfFBh6tU59EdXJ",
"os_platform": "ios",
"app_version": "2.8.6"
},
"json": {
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
},
"validate": [
{"check": "status_code", "expect": 200}
]
}
]
}
]
tests_mapping = {
"project_mapping": {
"functions": self.debugtalk_functions
},
"testcases": testcases
}
prepared_config_dict = parser.prepare_lazy_data(config_dict, self.debugtalk_functions)
test_runner = runner.Runner(prepared_config_dict, self.debugtalk_functions)
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
end_time = time.time()
# check if testcase setup hook executed
self.assertGreater(end_time - start_time, 0.5)
start_time = time.time()
test = {
"name": "get token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3",
"device_sn": "HZfFBh6tU59EdXJ",
"os_platform": "ios",
"app_version": "2.8.6"
},
"json": {
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
},
"validate": [
{"check": "status_code", "expect": 200}
]
}
test_runner.run_test(test)
test_runner.run_test(test)
test_runner.run_test(parsed_testcase["teststeps"][0])
end_time = time.time()
# testcase teardown hook has not been executed now
self.assertLess(end_time - start_time, 1)
def test_run_testcase_with_hooks_assignment(self):
config_dict = {
"name": "basic test with httpbin",
"base_url": HTTPBIN_SERVER
}
test = {
"name": "modify request headers",
"base_url": HTTPBIN_SERVER,
"request": {
"url": "/anything",
"method": "POST",
"headers": {
"user_agent": "iOS/10.3",
"os_platform": "ios"
testcases = [
{
"config": {
"name": "basic test with httpbin",
"base_url": HTTPBIN_SERVER
},
"data": "a=1&b=2"
"teststeps": [
{
"name": "modify request headers",
"base_url": HTTPBIN_SERVER,
"request": {
"url": "/anything",
"method": "POST",
"headers": {
"user_agent": "iOS/10.3",
"os_platform": "ios"
},
"data": "a=1&b=2"
},
"setup_hooks": [
{"total": "${sum_two(1, 5)}"}
],
"validate": [
{"check": "status_code", "expect": 200}
]
}
]
}
]
tests_mapping = {
"project_mapping": {
"functions": self.debugtalk_functions
},
"setup_hooks": [
{"total": "${sum_two(1, 5)}"}
],
"validate": [
{"check": "status_code", "expect": 200}
]
"testcases": testcases
}
parsed_test = parser.prepare_lazy_data(test, self.debugtalk_functions)
test_runner = runner.Runner(config_dict, self.debugtalk_functions)
test_runner.run_test(parsed_test)
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
test_runner.run_test(parsed_testcase["teststeps"][0])
test_variables_mapping = test_runner.session_context.test_variables_mapping
self.assertEqual(test_variables_mapping["total"], 6)
self.assertEqual(test_variables_mapping["request"]["data"], "a=1&b=2")
def test_run_testcase_with_hooks_modify_request(self):
config_dict = {
"name": "basic test with httpbin",
"base_url": HTTPBIN_SERVER
}
test = {
"name": "modify request headers",
"base_url": HTTPBIN_SERVER,
"request": {
"url": "/anything",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3"
testcases = [
{
"config": {
"name": "basic test with httpbin",
"base_url": HTTPBIN_SERVER
},
"json": {
"os_platform": "ios",
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
"teststeps": [
{
"name": "modify request headers",
"base_url": HTTPBIN_SERVER,
"request": {
"url": "/anything",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3"
},
"json": {
"os_platform": "ios",
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
},
"setup_hooks": [
"${modify_request_json($request, android)}"
],
"validate": [
{"check": "status_code", "expect": 200},
{"check": "content.json.os_platform", "expect": "android"}
]
}
]
}
]
tests_mapping = {
"project_mapping": {
"functions": self.debugtalk_functions
},
"setup_hooks": [
"${modify_request_json($request, android)}"
],
"validate": [
{"check": "status_code", "expect": 200},
{"check": "content.json.os_platform", "expect": "android"}
]
"testcases": testcases
}
test_runner = runner.Runner(config_dict, self.debugtalk_functions)
parsed_test = parser.prepare_lazy_data(test, self.debugtalk_functions, {"request"})
test_runner.run_test(parsed_test)
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
test_runner.run_test(parsed_testcase["teststeps"][0])
def test_run_testcase_with_teardown_hooks_success(self):
test = {
"name": "get token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3",
"device_sn": "HZfFBh6tU59EdXJ",
"os_platform": "ios",
"app_version": "2.8.6"
testcases = [
{
"config": {
"name": "basic test with httpbin"
},
"json": {
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
"teststeps": [
{
"name": "get token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3",
"device_sn": "HZfFBh6tU59EdXJ",
"os_platform": "ios",
"app_version": "2.8.6"
},
"json": {
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
},
"validate": [
{"check": "status_code", "expect": 200}
],
"teardown_hooks": ["${teardown_hook_sleep_N_secs($response, 2)}"]
}
]
}
]
tests_mapping = {
"project_mapping": {
"functions": self.debugtalk_functions
},
"validate": [
{"check": "status_code", "expect": 200}
],
"teardown_hooks": ["${teardown_hook_sleep_N_secs($response, 2)}"]
"testcases": testcases
}
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
start_time = time.time()
self.test_runner.run_test(test)
test_runner.run_test(parsed_testcase["teststeps"][0])
end_time = time.time()
# check if teardown function executed
self.assertLess(end_time - start_time, 0.5)
def test_run_testcase_with_teardown_hooks_fail(self):
test = {
"name": "get token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token2",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3",
"device_sn": "HZfFBh6tU59EdXJ",
"os_platform": "ios",
"app_version": "2.8.6"
testcases = [
{
"config": {
"name": "basic test with httpbin"
},
"json": {
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
"teststeps": [
{
"name": "get token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token2",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3",
"device_sn": "HZfFBh6tU59EdXJ",
"os_platform": "ios",
"app_version": "2.8.6"
},
"json": {
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
},
"validate": [
{"check": "status_code", "expect": 404}
],
"teardown_hooks": ["${teardown_hook_sleep_N_secs($response, 2)}"]
}
]
}
]
tests_mapping = {
"project_mapping": {
"functions": self.debugtalk_functions
},
"validate": [
{"check": "status_code", "expect": 404}
],
"teardown_hooks": ["${teardown_hook_sleep_N_secs($response, 2)}"]
"testcases": testcases
}
prepared_test = parser.prepare_lazy_data(test, self.debugtalk_functions, {"response"})
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
start_time = time.time()
self.test_runner.run_test(prepared_test)
test_runner.run_test(parsed_testcase["teststeps"][0])
end_time = time.time()
# check if teardown function executed
self.assertGreater(end_time - start_time, 2)
@@ -251,34 +289,51 @@ class TestRunner(ApiServerUnittest):
def test_bugfix_type_match(self):
testcase_file_path = os.path.join(
os.getcwd(), 'tests/data/bugfix_type_match.yml')
testcases = loader.load_file(testcase_file_path)
test = testcases[1]["test"]
self.test_runner.run_test(test)
tests_mapping = loader.load_tests(testcase_file_path)
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
test_runner.run_test(parsed_testcase["teststeps"][0])
def test_run_validate_elapsed(self):
test = {
"name": "get token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3",
"device_sn": "HZfFBh6tU59EdXJ",
"os_platform": "ios",
"app_version": "2.8.6"
},
"json": {
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
testcases = [
{
"config": {},
"teststeps": [
{
"name": "get token",
"request": {
"url": "http://127.0.0.1:5000/api/get-token",
"method": "POST",
"headers": {
"content-type": "application/json",
"user_agent": "iOS/10.3",
"device_sn": "HZfFBh6tU59EdXJ",
"os_platform": "ios",
"app_version": "2.8.6"
},
"json": {
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
}
},
"validate": [
{"check": "status_code", "expect": 200},
{"check": "elapsed.seconds", "comparator": "lt", "expect": 1},
{"check": "elapsed.days", "comparator": "eq", "expect": 0},
{"check": "elapsed.microseconds", "comparator": "gt", "expect": 1000},
{"check": "elapsed.total_seconds", "comparator": "lt", "expect": 1}
]
}
]
}
]
tests_mapping = {
"project_mapping": {
"functions": self.debugtalk_functions
},
"validate": [
{"check": "status_code", "expect": 200},
{"check": "elapsed.seconds", "comparator": "lt", "expect": 1},
{"check": "elapsed.days", "comparator": "eq", "expect": 0},
{"check": "elapsed.microseconds", "comparator": "gt", "expect": 1000},
{"check": "elapsed.total_seconds", "comparator": "lt", "expect": 1}
]
"testcases": testcases
}
self.test_runner.run_test(test)
parsed_tests_mapping = parser.parse_tests(tests_mapping)
parsed_testcase = parsed_tests_mapping["testcases"][0]
test_runner = runner.Runner(parsed_testcase["config"])
test_runner.run_test(parsed_testcase["teststeps"][0])

View File

@@ -61,35 +61,6 @@ class TestUtils(ApiServerUnittest):
result = utils.query_json(json_content, query)
self.assertEqual(result, "L")
def test_get_uniform_comparator(self):
self.assertEqual(utils.get_uniform_comparator("eq"), "equals")
self.assertEqual(utils.get_uniform_comparator("=="), "equals")
self.assertEqual(utils.get_uniform_comparator("lt"), "less_than")
self.assertEqual(utils.get_uniform_comparator("le"), "less_than_or_equals")
self.assertEqual(utils.get_uniform_comparator("gt"), "greater_than")
self.assertEqual(utils.get_uniform_comparator("ge"), "greater_than_or_equals")
self.assertEqual(utils.get_uniform_comparator("ne"), "not_equals")
self.assertEqual(utils.get_uniform_comparator("str_eq"), "string_equals")
self.assertEqual(utils.get_uniform_comparator("len_eq"), "length_equals")
self.assertEqual(utils.get_uniform_comparator("count_eq"), "length_equals")
self.assertEqual(utils.get_uniform_comparator("len_gt"), "length_greater_than")
self.assertEqual(utils.get_uniform_comparator("count_gt"), "length_greater_than")
self.assertEqual(utils.get_uniform_comparator("count_greater_than"), "length_greater_than")
self.assertEqual(utils.get_uniform_comparator("len_ge"), "length_greater_than_or_equals")
self.assertEqual(utils.get_uniform_comparator("count_ge"), "length_greater_than_or_equals")
self.assertEqual(utils.get_uniform_comparator("count_greater_than_or_equals"), "length_greater_than_or_equals")
self.assertEqual(utils.get_uniform_comparator("len_lt"), "length_less_than")
self.assertEqual(utils.get_uniform_comparator("count_lt"), "length_less_than")
self.assertEqual(utils.get_uniform_comparator("count_less_than"), "length_less_than")
self.assertEqual(utils.get_uniform_comparator("len_le"), "length_less_than_or_equals")
self.assertEqual(utils.get_uniform_comparator("count_le"), "length_less_than_or_equals")
self.assertEqual(utils.get_uniform_comparator("count_less_than_or_equals"), "length_less_than_or_equals")
def current_validators(self):
from httprunner import built_in
functions_mapping = loader.load_module_functions(built_in)
@@ -205,61 +176,6 @@ class TestUtils(ApiServerUnittest):
self.assertIsInstance(ordered_dict, dict)
self.assertIn("a", ordered_dict)
def test_extend_validators(self):
def_validators = [
{'eq': ['v1', 200]},
{"check": "s2", "expect": 16, "comparator": "len_eq"}
]
current_validators = [
{"check": "v1", "expect": 201},
{'len_eq': ['s3', 12]}
]
def_validators = [
parser.parse_validator(validator)
for validator in def_validators
]
ref_validators = [
parser.parse_validator(validator)
for validator in current_validators
]
extended_validators = utils.extend_validators(def_validators, ref_validators)
self.assertIn(
{"check": "v1", "expect": 201, "comparator": "eq"},
extended_validators
)
self.assertIn(
{"check": "s2", "expect": 16, "comparator": "len_eq"},
extended_validators
)
self.assertIn(
{"check": "s3", "expect": 12, "comparator": "len_eq"},
extended_validators
)
def test_extend_validators_with_dict(self):
def_validators = [
{'eq': ["a", {"v": 1}]},
{'eq': [{"b": 1}, 200]}
]
current_validators = [
{'len_eq': ['s3', 12]},
{'eq': [{"b": 1}, 201]}
]
def_validators = [
parser.parse_validator(validator)
for validator in def_validators
]
ref_validators = [
parser.parse_validator(validator)
for validator in current_validators
]
extended_validators = utils.extend_validators(def_validators, ref_validators)
self.assertEqual(len(extended_validators), 3)
self.assertIn({'check': {'b': 1}, 'expect': 201, 'comparator': 'eq'}, extended_validators)
self.assertNotIn({'check': {'b': 1}, 'expect': 200, 'comparator': 'eq'}, extended_validators)
def test_extend_variables(self):
raw_variables = [{"var1": "val1"}, {"var2": "val2"}]
override_variables = [{"var1": "val111"}, {"var3": "val3"}]

View File

@@ -74,3 +74,101 @@ class TestValidator(unittest.TestCase):
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):
self.assertEqual(validator.get_uniform_comparator("eq"), "equals")
self.assertEqual(validator.get_uniform_comparator("=="), "equals")
self.assertEqual(validator.get_uniform_comparator("lt"), "less_than")
self.assertEqual(validator.get_uniform_comparator("le"), "less_than_or_equals")
self.assertEqual(validator.get_uniform_comparator("gt"), "greater_than")
self.assertEqual(validator.get_uniform_comparator("ge"), "greater_than_or_equals")
self.assertEqual(validator.get_uniform_comparator("ne"), "not_equals")
self.assertEqual(validator.get_uniform_comparator("str_eq"), "string_equals")
self.assertEqual(validator.get_uniform_comparator("len_eq"), "length_equals")
self.assertEqual(validator.get_uniform_comparator("count_eq"), "length_equals")
self.assertEqual(validator.get_uniform_comparator("len_gt"), "length_greater_than")
self.assertEqual(validator.get_uniform_comparator("count_gt"), "length_greater_than")
self.assertEqual(validator.get_uniform_comparator("count_greater_than"), "length_greater_than")
self.assertEqual(validator.get_uniform_comparator("len_ge"), "length_greater_than_or_equals")
self.assertEqual(validator.get_uniform_comparator("count_ge"), "length_greater_than_or_equals")
self.assertEqual(validator.get_uniform_comparator("count_greater_than_or_equals"), "length_greater_than_or_equals")
self.assertEqual(validator.get_uniform_comparator("len_lt"), "length_less_than")
self.assertEqual(validator.get_uniform_comparator("count_lt"), "length_less_than")
self.assertEqual(validator.get_uniform_comparator("count_less_than"), "length_less_than")
self.assertEqual(validator.get_uniform_comparator("len_le"), "length_less_than_or_equals")
self.assertEqual(validator.get_uniform_comparator("count_le"), "length_less_than_or_equals")
self.assertEqual(validator.get_uniform_comparator("count_less_than_or_equals"), "length_less_than_or_equals")
def test_parse_validator(self):
_validator = {"check": "status_code", "comparator": "eq", "expect": 201}
self.assertEqual(
validator.uniform_validator(_validator),
{"check": "status_code", "comparator": "equals", "expect": 201}
)
_validator = {'eq': ['status_code', 201]}
self.assertEqual(
validator.uniform_validator(_validator),
{"check": "status_code", "comparator": "equals", "expect": 201}
)
def test_extend_validators(self):
def_validators = [
{'eq': ['v1', 200]},
{"check": "s2", "expect": 16, "comparator": "len_eq"}
]
current_validators = [
{"check": "v1", "expect": 201},
{'len_eq': ['s3', 12]}
]
def_validators = [
validator.uniform_validator(_validator)
for _validator in def_validators
]
ref_validators = [
validator.uniform_validator(_validator)
for _validator in current_validators
]
extended_validators = validator.extend_validators(def_validators, ref_validators)
self.assertIn(
{"check": "v1", "expect": 201, "comparator": "equals"},
extended_validators
)
self.assertIn(
{"check": "s2", "expect": 16, "comparator": "length_equals"},
extended_validators
)
self.assertIn(
{"check": "s3", "expect": 12, "comparator": "length_equals"},
extended_validators
)
def test_extend_validators_with_dict(self):
def_validators = [
{'eq': ["a", {"v": 1}]},
{'eq': [{"b": 1}, 200]}
]
current_validators = [
{'len_eq': ['s3', 12]},
{'eq': [{"b": 1}, 201]}
]
def_validators = [
validator.uniform_validator(_validator)
for _validator in def_validators
]
ref_validators = [
validator.uniform_validator(_validator)
for _validator in current_validators
]
extended_validators = validator.extend_validators(def_validators, ref_validators)
self.assertEqual(len(extended_validators), 3)
self.assertIn({'check': {'b': 1}, 'expect': 201, 'comparator': 'equals'}, extended_validators)
self.assertNotIn({'check': {'b': 1}, 'expect': 200, 'comparator': 'equals'}, extended_validators)