mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-31 21:39:41 +08:00
@@ -1,5 +1,11 @@
|
|||||||
# Release History
|
# Release History
|
||||||
|
|
||||||
|
## 2.1.0 (2019-03-19)
|
||||||
|
|
||||||
|
**Features**
|
||||||
|
|
||||||
|
- implement json dump Python objects when save tests
|
||||||
|
|
||||||
## 2.0.6 (2019-03-18)
|
## 2.0.6 (2019-03-18)
|
||||||
|
|
||||||
**Features**
|
**Features**
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
__title__ = 'HttpRunner'
|
__title__ = 'HttpRunner'
|
||||||
__description__ = 'One-stop solution for HTTP(S) testing.'
|
__description__ = 'One-stop solution for HTTP(S) testing.'
|
||||||
__url__ = 'https://github.com/HttpRunner/HttpRunner'
|
__url__ = 'https://github.com/HttpRunner/HttpRunner'
|
||||||
__version__ = '2.0.6'
|
__version__ = '2.1.0'
|
||||||
__author__ = 'debugtalk'
|
__author__ = 'debugtalk'
|
||||||
__author_email__ = 'mail@debugtalk.com'
|
__author_email__ = 'mail@debugtalk.com'
|
||||||
__license__ = 'Apache-2.0'
|
__license__ = 'Apache-2.0'
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ class HttpRunner(object):
|
|||||||
if log_file:
|
if log_file:
|
||||||
logger.setup_logger(log_level, log_file)
|
logger.setup_logger(log_level, log_file)
|
||||||
|
|
||||||
def _add_tests(self, tests_mapping):
|
def _add_tests(self, testcases):
|
||||||
""" initialize testcase with Runner() and add to test suite.
|
""" initialize testcase with Runner() and add to test suite.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tests_mapping (dict): project info and testcases list.
|
testcases (list): testcases list.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
unittest.TestSuite()
|
unittest.TestSuite()
|
||||||
@@ -60,18 +60,23 @@ class HttpRunner(object):
|
|||||||
if "config" in test_dict:
|
if "config" in test_dict:
|
||||||
# run nested testcase
|
# run nested testcase
|
||||||
test.__doc__ = test_dict["config"].get("name")
|
test.__doc__ = test_dict["config"].get("name")
|
||||||
|
variables = test_dict["config"].get("variables", {})
|
||||||
else:
|
else:
|
||||||
# run api test
|
# run api test
|
||||||
test.__doc__ = test_dict.get("name")
|
test.__doc__ = test_dict.get("name")
|
||||||
|
variables = test_dict.get("variables", {})
|
||||||
|
|
||||||
|
if isinstance(test.__doc__, parser.LazyString):
|
||||||
|
parsed_variables = parser.parse_variables_mapping(variables, ignore=True)
|
||||||
|
test.__doc__ = parser.parse_lazy_data(
|
||||||
|
test.__doc__, parsed_variables)
|
||||||
|
|
||||||
return test
|
return test
|
||||||
|
|
||||||
test_suite = unittest.TestSuite()
|
test_suite = unittest.TestSuite()
|
||||||
functions = tests_mapping.get("project_mapping", {}).get("functions", {})
|
for testcase in testcases:
|
||||||
|
|
||||||
for testcase in tests_mapping["testcases"]:
|
|
||||||
config = testcase.get("config", {})
|
config = testcase.get("config", {})
|
||||||
test_runner = runner.Runner(config, functions)
|
test_runner = runner.Runner(config)
|
||||||
TestSequense = type('TestSequense', (unittest.TestCase,), {})
|
TestSequense = type('TestSequense', (unittest.TestCase,), {})
|
||||||
|
|
||||||
tests = testcase.get("teststeps", [])
|
tests = testcase.get("teststeps", [])
|
||||||
@@ -157,19 +162,20 @@ class HttpRunner(object):
|
|||||||
def run_tests(self, tests_mapping):
|
def run_tests(self, tests_mapping):
|
||||||
""" run testcase/testsuite data
|
""" run testcase/testsuite data
|
||||||
"""
|
"""
|
||||||
|
project_mapping = tests_mapping.get("project_mapping", {})
|
||||||
if self.save_tests:
|
if self.save_tests:
|
||||||
utils.dump_tests(tests_mapping, "loaded")
|
utils.dump_logs(tests_mapping, project_mapping, "loaded")
|
||||||
|
|
||||||
# parse tests
|
# parse tests
|
||||||
self.exception_stage = "parse tests"
|
self.exception_stage = "parse tests"
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
|
|
||||||
if self.save_tests:
|
if self.save_tests:
|
||||||
utils.dump_tests(parsed_tests_mapping, "parsed")
|
utils.dump_logs(parsed_testcases, project_mapping, "parsed")
|
||||||
|
|
||||||
# add tests to test suite
|
# add tests to test suite
|
||||||
self.exception_stage = "add tests to test suite"
|
self.exception_stage = "add tests to test suite"
|
||||||
test_suite = self._add_tests(parsed_tests_mapping)
|
test_suite = self._add_tests(parsed_testcases)
|
||||||
|
|
||||||
# run test suite
|
# run test suite
|
||||||
self.exception_stage = "run test suite"
|
self.exception_stage = "run test suite"
|
||||||
@@ -184,7 +190,7 @@ class HttpRunner(object):
|
|||||||
report.stringify_summary(self._summary)
|
report.stringify_summary(self._summary)
|
||||||
|
|
||||||
if self.save_tests:
|
if self.save_tests:
|
||||||
utils.dump_summary(self._summary, tests_mapping["project_mapping"])
|
utils.dump_logs(self._summary, project_mapping, "summary")
|
||||||
|
|
||||||
report_path = report.render_html_report(
|
report_path = report.render_html_report(
|
||||||
self._summary,
|
self._summary,
|
||||||
@@ -275,27 +281,22 @@ def prepare_locust_tests(path):
|
|||||||
path (str): testcase file path.
|
path (str): testcase file path.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: locust tests data
|
list: locust tests data
|
||||||
|
|
||||||
{
|
[
|
||||||
"functions": {},
|
testcase1_dict,
|
||||||
"tests": []
|
testcase2_dict
|
||||||
}
|
]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
tests_mapping = loader.load_tests(path)
|
tests_mapping = loader.load_tests(path)
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
testcases = parser.parse_tests(tests_mapping)
|
||||||
|
|
||||||
functions = parsed_tests_mapping.get("project_mapping", {}).get("functions", {})
|
locust_tests = []
|
||||||
|
|
||||||
tests = []
|
for testcase in testcases:
|
||||||
|
|
||||||
for testcase in parsed_tests_mapping["testcases"]:
|
|
||||||
testcase_weight = testcase.get("config", {}).pop("weight", 1)
|
testcase_weight = testcase.get("config", {}).pop("weight", 1)
|
||||||
for _ in range(testcase_weight):
|
for _ in range(testcase_weight):
|
||||||
tests.append(testcase)
|
locust_tests.append(testcase)
|
||||||
|
|
||||||
return {
|
return locust_tests
|
||||||
"functions": functions,
|
|
||||||
"tests": tests
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ def main_hrun():
|
|||||||
from httprunner.__about__ import __description__, __version__
|
from httprunner.__about__ 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.validator import validate_json_file
|
||||||
from httprunner.utils import (create_scaffold, get_python2_retire_msg,
|
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 = argparse.ArgumentParser(description=__description__)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import time
|
|||||||
import requests
|
import requests
|
||||||
import urllib3
|
import urllib3
|
||||||
from httprunner import logger
|
from httprunner import logger
|
||||||
from httprunner.utils import build_url, lower_dict_keys, omit_long_data
|
from httprunner.utils import lower_dict_keys, omit_long_data
|
||||||
from requests import Request, Response
|
from requests import Request, Response
|
||||||
from requests.exceptions import (InvalidSchema, InvalidURL, MissingSchema,
|
from requests.exceptions import (InvalidSchema, InvalidURL, MissingSchema,
|
||||||
RequestException)
|
RequestException)
|
||||||
@@ -28,15 +28,10 @@ class HttpSession(requests.Session):
|
|||||||
display statistics.
|
display statistics.
|
||||||
|
|
||||||
This is a slightly extended version of `python-request <http://python-requests.org>`_'s
|
This is a slightly extended version of `python-request <http://python-requests.org>`_'s
|
||||||
:py:class:`requests.Session` class and mostly this class works exactly the same. However
|
:py:class:`requests.Session` class and mostly this class works exactly the same.
|
||||||
the methods for making requests (get, post, delete, put, head, options, patch, request)
|
|
||||||
can now take a *url* argument that's only the path part of the URL, in which case the host
|
|
||||||
part of the URL will be prepended with the HttpSession.base_url which is normally inherited
|
|
||||||
from a HttpRunner class' host property.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, base_url=None, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(HttpSession, self).__init__(*args, **kwargs)
|
super(HttpSession, self).__init__(*args, **kwargs)
|
||||||
self.base_url = base_url if base_url else ""
|
|
||||||
self.init_meta_data()
|
self.init_meta_data()
|
||||||
|
|
||||||
def init_meta_data(self):
|
def init_meta_data(self):
|
||||||
@@ -180,9 +175,6 @@ class HttpSession(requests.Session):
|
|||||||
kwargs.setdefault("timeout", 120)
|
kwargs.setdefault("timeout", 120)
|
||||||
self.meta_data["data"][0]["request"].update(kwargs)
|
self.meta_data["data"][0]["request"].update(kwargs)
|
||||||
|
|
||||||
# prepend url with hostname unless it's already an absolute URL
|
|
||||||
url = build_url(self.base_url, url)
|
|
||||||
|
|
||||||
start_timestamp = time.time()
|
start_timestamp = time.time()
|
||||||
response = self._send_request_safe_mode(method, url, **kwargs)
|
response = self._send_request_safe_mode(method, url, **kwargs)
|
||||||
response_time_ms = round((time.time() - start_timestamp) * 1000, 2)
|
response_time_ms = round((time.time() - start_timestamp) * 1000, 2)
|
||||||
|
|||||||
@@ -5,18 +5,17 @@ class SessionContext(object):
|
|||||||
""" HttpRunner session, store runtime variables.
|
""" HttpRunner session, store runtime variables.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
>>> functions={...}
|
|
||||||
>>> variables = {"SECRET_KEY": "DebugTalk"}
|
>>> variables = {"SECRET_KEY": "DebugTalk"}
|
||||||
>>> context = SessionContext(functions, variables)
|
>>> context = SessionContext(variables)
|
||||||
|
|
||||||
Equivalent to:
|
Equivalent to:
|
||||||
>>> context = SessionContext(functions)
|
>>> context = SessionContext()
|
||||||
>>> context.update_session_variables(variables)
|
>>> 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 {})
|
variables_mapping = utils.ensure_mapping_format(variables or {})
|
||||||
self.FUNCTIONS_MAPPING = functions
|
self.session_variables_mapping = parser.parse_variables_mapping(variables_mapping)
|
||||||
self.init_test_variables()
|
self.init_test_variables()
|
||||||
self.validation_results = []
|
self.validation_results = []
|
||||||
|
|
||||||
@@ -36,16 +35,14 @@ class SessionContext(object):
|
|||||||
"""
|
"""
|
||||||
variables_mapping = variables_mapping or {}
|
variables_mapping = variables_mapping or {}
|
||||||
variables_mapping = utils.ensure_mapping_format(variables_mapping)
|
variables_mapping = utils.ensure_mapping_format(variables_mapping)
|
||||||
|
variables_mapping.update(self.session_variables_mapping)
|
||||||
|
parsed_variables_mapping = parser.parse_variables_mapping(variables_mapping)
|
||||||
|
|
||||||
self.test_variables_mapping = {}
|
self.test_variables_mapping = {}
|
||||||
# priority: extracted variable > teststep variable
|
# priority: extracted variable > teststep variable
|
||||||
self.test_variables_mapping.update(variables_mapping)
|
self.test_variables_mapping.update(parsed_variables_mapping)
|
||||||
self.test_variables_mapping.update(self.session_variables_mapping)
|
self.test_variables_mapping.update(self.session_variables_mapping)
|
||||||
|
|
||||||
for variable_name, variable_value in variables_mapping.items():
|
|
||||||
variable_value = self.eval_content(variable_value)
|
|
||||||
self.update_test_variables(variable_name, variable_value)
|
|
||||||
|
|
||||||
def update_test_variables(self, variable_name, variable_value):
|
def update_test_variables(self, variable_name, variable_value):
|
||||||
""" update test variables, these variables are only valid in the current test.
|
""" update test variables, these variables are only valid in the current test.
|
||||||
"""
|
"""
|
||||||
@@ -63,110 +60,46 @@ class SessionContext(object):
|
|||||||
""" evaluate content recursively, take effect on each variable and function in content.
|
""" evaluate content recursively, take effect on each variable and function in content.
|
||||||
content may be in any data structure, include dict, list, tuple, number, string, etc.
|
content may be in any data structure, include dict, list, tuple, number, string, etc.
|
||||||
"""
|
"""
|
||||||
return parser.parse_data(
|
return parser.parse_lazy_data(content, self.test_variables_mapping)
|
||||||
content,
|
|
||||||
self.test_variables_mapping,
|
|
||||||
self.FUNCTIONS_MAPPING
|
|
||||||
)
|
|
||||||
|
|
||||||
def __eval_check_item(self, validator, resp_obj):
|
def __eval_validator_check(self, check_item, resp_obj):
|
||||||
""" evaluate check item in validator.
|
""" evaluate check item in validator.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
validator (dict): validator
|
check_item: check_item should only be the following 5 formats:
|
||||||
{"check": "status_code", "comparator": "eq", "expect": 201}
|
1, variable reference, e.g. $token
|
||||||
{"check": "$resp_body_success", "comparator": "eq", "expect": True}
|
2, function reference, e.g. ${is_status_code_200($status_code)}
|
||||||
resp_obj (object): requests.Response() object
|
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:
|
resp_obj: response object
|
||||||
dict: validator info
|
|
||||||
{
|
|
||||||
"check": "status_code",
|
|
||||||
"check_value": 200,
|
|
||||||
"expect": 201,
|
|
||||||
"comparator": "eq"
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
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)) \
|
if isinstance(check_item, (dict, list)) \
|
||||||
or parser.extract_variables(check_item) \
|
or isinstance(check_item, parser.LazyString):
|
||||||
or parser.extract_functions(check_item):
|
|
||||||
# format 1/2/3
|
# format 1/2/3
|
||||||
check_value = self.eval_content(check_item)
|
check_value = self.eval_content(check_item)
|
||||||
else:
|
else:
|
||||||
# format 4/5
|
# format 4/5
|
||||||
check_value = resp_obj.extract_field(check_item)
|
check_value = resp_obj.extract_field(check_item)
|
||||||
|
|
||||||
validator["check_value"] = check_value
|
return check_value
|
||||||
|
|
||||||
# expect_value should only be in 2 types:
|
def __eval_validator_expect(self, expect_item):
|
||||||
# 1, variable reference, e.g. $expect_status_code
|
""" evaluate expect item in validator.
|
||||||
# 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
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
validator_dict (dict): validator dict
|
expect_item: expect_item should only be in 2 types:
|
||||||
{
|
1, variable reference, e.g. $expect_status_code
|
||||||
"check": "status_code",
|
2, actual value, e.g. 200
|
||||||
"check_value": 200,
|
|
||||||
"expect": 201,
|
|
||||||
"comparator": "eq"
|
|
||||||
}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# TODO: move comparator uniform to init_test_suites
|
expect_value = self.eval_content(expect_item)
|
||||||
comparator = utils.get_uniform_comparator(validator_dict["comparator"])
|
return expect_value
|
||||||
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)
|
|
||||||
|
|
||||||
def validate(self, validators, resp_obj):
|
def validate(self, validators, resp_obj):
|
||||||
""" make validations
|
""" make validation with comparators
|
||||||
"""
|
"""
|
||||||
self.validation_results = []
|
self.validation_results = []
|
||||||
if not validators:
|
if not validators:
|
||||||
@@ -178,19 +111,59 @@ class SessionContext(object):
|
|||||||
failures = []
|
failures = []
|
||||||
|
|
||||||
for validator in validators:
|
for validator in validators:
|
||||||
# evaluate validators with context variable mapping.
|
# validator should be LazyFunction object
|
||||||
evaluated_validator = self.__eval_check_item(
|
if not isinstance(validator, parser.LazyFunction):
|
||||||
parser.parse_validator(validator),
|
raise exceptions.ValidationFailure(
|
||||||
|
"validator should be parsed first: {}".format(validators))
|
||||||
|
|
||||||
|
# evaluate validator args with context variable mapping.
|
||||||
|
validator_args = validator.get_args()
|
||||||
|
check_item, expect_item = validator_args
|
||||||
|
check_value = self.__eval_validator_check(
|
||||||
|
check_item,
|
||||||
resp_obj
|
resp_obj
|
||||||
)
|
)
|
||||||
|
expect_value = self.__eval_validator_expect(expect_item)
|
||||||
|
validator.update_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:
|
try:
|
||||||
self._do_validation(evaluated_validator)
|
validator.to_value(self.test_variables_mapping)
|
||||||
except exceptions.ValidationFailure as ex:
|
validator_dict["check_result"] = "pass"
|
||||||
|
validate_msg += "\t==> pass"
|
||||||
|
logger.log_debug(validate_msg)
|
||||||
|
except (AssertionError, TypeError):
|
||||||
validate_pass = False
|
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.update_args(validator_args)
|
||||||
|
|
||||||
if not validate_pass:
|
if not validate_pass:
|
||||||
failures_string = "\n".join([failure for failure in failures])
|
failures_string = "\n".join([failure for failure in failures])
|
||||||
|
|||||||
1086
httprunner/parser.py
1086
httprunner/parser.py
File diff suppressed because it is too large
Load Diff
@@ -11,27 +11,40 @@ class Runner(object):
|
|||||||
""" Running testcases.
|
""" Running testcases.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
>>> functions={...}
|
>>> tests_mapping = {
|
||||||
>>> config = {
|
"project_mapping": {
|
||||||
"name": "XXXX",
|
"functions": {}
|
||||||
"base_url": "http://127.0.0.1",
|
},
|
||||||
"verify": False
|
"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 = {
|
>>> testcases = parser.parse_tests(tests_mapping)
|
||||||
"name": "test description",
|
>>> parsed_testcase = testcases[0]
|
||||||
"variables": [], # optional
|
|
||||||
"request": {
|
>>> test_runner = runner.Runner(parsed_testcase["config"])
|
||||||
"url": "http://127.0.0.1:5000/api/users/1000",
|
>>> test_runner.run_test(parsed_testcase["teststeps"][0])
|
||||||
"method": "GET"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>>> runner.run_test(test_dict)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, config, functions, http_client_session=None):
|
def __init__(self, config, http_client_session=None):
|
||||||
""" run testcase or testsuite.
|
""" run testcase or testsuite.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -47,19 +60,18 @@ class Runner(object):
|
|||||||
http_client_session (instance): requests.Session(), or locust.client.Session() instance.
|
http_client_session (instance): requests.Session(), or locust.client.Session() instance.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
base_url = config.get("base_url")
|
|
||||||
self.verify = config.get("verify", True)
|
self.verify = config.get("verify", True)
|
||||||
self.output = config.get("output", [])
|
self.output = config.get("output", [])
|
||||||
self.functions = functions
|
|
||||||
self.validation_results = []
|
self.validation_results = []
|
||||||
|
config_variables = config.get("variables", {})
|
||||||
|
|
||||||
# testcase setup hooks
|
# testcase setup hooks
|
||||||
testcase_setup_hooks = config.get("setup_hooks", [])
|
testcase_setup_hooks = config.get("setup_hooks", [])
|
||||||
# testcase teardown hooks
|
# testcase teardown hooks
|
||||||
self.testcase_teardown_hooks = config.get("teardown_hooks", [])
|
self.testcase_teardown_hooks = config.get("teardown_hooks", [])
|
||||||
|
|
||||||
self.http_client_session = http_client_session or HttpSession(base_url)
|
self.http_client_session = http_client_session or HttpSession()
|
||||||
self.session_context = SessionContext(self.functions)
|
self.session_context = SessionContext(config_variables)
|
||||||
|
|
||||||
if testcase_setup_hooks:
|
if testcase_setup_hooks:
|
||||||
self.do_hook_actions(testcase_setup_hooks, "setup")
|
self.do_hook_actions(testcase_setup_hooks, "setup")
|
||||||
@@ -199,20 +211,24 @@ class Runner(object):
|
|||||||
self.session_context.init_test_variables(test_variables)
|
self.session_context.init_test_variables(test_variables)
|
||||||
|
|
||||||
# teststep name
|
# teststep name
|
||||||
test_name = test_dict.get("name", "")
|
test_name = self.session_context.eval_content(test_dict.get("name", ""))
|
||||||
|
|
||||||
# parse test request
|
# parse test request
|
||||||
raw_request = test_dict.get('request', {})
|
raw_request = test_dict.get('request', {})
|
||||||
parsed_test_request = self.session_context.eval_content(raw_request)
|
parsed_test_request = self.session_context.eval_content(raw_request)
|
||||||
self.session_context.update_test_variables("request", parsed_test_request)
|
self.session_context.update_test_variables("request", parsed_test_request)
|
||||||
|
|
||||||
|
# prepend url with base_url unless it's already an absolute URL
|
||||||
|
url = parsed_test_request.pop('url')
|
||||||
|
base_url = self.session_context.eval_content(test_dict.get("base_url", ""))
|
||||||
|
parsed_url = utils.build_url(base_url, url)
|
||||||
|
|
||||||
# setup hooks
|
# setup hooks
|
||||||
setup_hooks = test_dict.get("setup_hooks", [])
|
setup_hooks = test_dict.get("setup_hooks", [])
|
||||||
if setup_hooks:
|
if setup_hooks:
|
||||||
self.do_hook_actions(setup_hooks, "setup")
|
self.do_hook_actions(setup_hooks, "setup")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
url = parsed_test_request.pop('url')
|
|
||||||
method = parsed_test_request.pop('method')
|
method = parsed_test_request.pop('method')
|
||||||
parsed_test_request.setdefault("verify", self.verify)
|
parsed_test_request.setdefault("verify", self.verify)
|
||||||
group_name = parsed_test_request.pop("group", None)
|
group_name = parsed_test_request.pop("group", None)
|
||||||
@@ -227,13 +243,13 @@ class Runner(object):
|
|||||||
logger.log_error(err_msg)
|
logger.log_error(err_msg)
|
||||||
raise exceptions.ParamsError(err_msg)
|
raise exceptions.ParamsError(err_msg)
|
||||||
|
|
||||||
logger.log_info("{method} {url}".format(method=method, url=url))
|
logger.log_info("{method} {url}".format(method=method, url=parsed_url))
|
||||||
logger.log_debug("request kwargs(raw): {kwargs}".format(kwargs=parsed_test_request))
|
logger.log_debug("request kwargs(raw): {kwargs}".format(kwargs=parsed_test_request))
|
||||||
|
|
||||||
# request
|
# request
|
||||||
resp = self.http_client_session.request(
|
resp = self.http_client_session.request(
|
||||||
method,
|
method,
|
||||||
url,
|
parsed_url,
|
||||||
name=(group_name or test_name),
|
name=(group_name or test_name),
|
||||||
**parsed_test_request
|
**parsed_test_request
|
||||||
)
|
)
|
||||||
@@ -254,13 +270,12 @@ class Runner(object):
|
|||||||
validators = test_dict.get("validate", [])
|
validators = test_dict.get("validate", [])
|
||||||
try:
|
try:
|
||||||
self.session_context.validate(validators, resp_obj)
|
self.session_context.validate(validators, resp_obj)
|
||||||
|
|
||||||
except (exceptions.ParamsError, exceptions.ValidationFailure, exceptions.ExtractFailure):
|
except (exceptions.ParamsError, exceptions.ValidationFailure, exceptions.ExtractFailure):
|
||||||
err_msg = "{} DETAILED REQUEST & RESPONSE {}\n".format("*" * 32, "*" * 32)
|
err_msg = "{} DETAILED REQUEST & RESPONSE {}\n".format("*" * 32, "*" * 32)
|
||||||
|
|
||||||
# log request
|
# log request
|
||||||
err_msg += "====== request details ======\n"
|
err_msg += "====== request details ======\n"
|
||||||
err_msg += "url: {}\n".format(url)
|
err_msg += "url: {}\n".format(parsed_url)
|
||||||
err_msg += "method: {}\n".format(method)
|
err_msg += "method: {}\n".format(method)
|
||||||
err_msg += "headers: {}\n".format(parsed_test_request.pop("headers", {}))
|
err_msg += "headers: {}\n".format(parsed_test_request.pop("headers", {}))
|
||||||
for k, v in parsed_test_request.items():
|
for k, v in parsed_test_request.items():
|
||||||
@@ -288,7 +303,7 @@ class Runner(object):
|
|||||||
config = testcase_dict.get("config", {})
|
config = testcase_dict.get("config", {})
|
||||||
|
|
||||||
# each teststeps in one testcase (YAML/JSON) share the same session.
|
# 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", [])
|
tests = testcase_dict.get("teststeps", [])
|
||||||
|
|
||||||
@@ -351,6 +366,9 @@ class Runner(object):
|
|||||||
self.meta_datas = None
|
self.meta_datas = None
|
||||||
if "teststeps" in test_dict:
|
if "teststeps" in test_dict:
|
||||||
# nested testcase
|
# nested testcase
|
||||||
|
test_dict.setdefault("config", {}).setdefault("variables", {})
|
||||||
|
test_dict["config"]["variables"].update(
|
||||||
|
self.session_context.session_variables_mapping)
|
||||||
self._run_testcase(test_dict)
|
self._run_testcase(test_dict)
|
||||||
else:
|
else:
|
||||||
# api
|
# api
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ logging.getLogger('locust.runners').setLevel(logging.INFO)
|
|||||||
|
|
||||||
class WebPageTasks(TaskSet):
|
class WebPageTasks(TaskSet):
|
||||||
def on_start(self):
|
def on_start(self):
|
||||||
self.test_runner = Runner(self.locust.config, self.locust.functions, self.client)
|
config = {}
|
||||||
|
self.test_runner = Runner(config, self.client)
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def test_any(self):
|
def test_any(self):
|
||||||
@@ -32,14 +33,10 @@ class WebPageTasks(TaskSet):
|
|||||||
|
|
||||||
|
|
||||||
class WebPageUser(HttpLocust):
|
class WebPageUser(HttpLocust):
|
||||||
|
host = ""
|
||||||
task_set = WebPageTasks
|
task_set = WebPageTasks
|
||||||
min_wait = 10
|
min_wait = 10
|
||||||
max_wait = 30
|
max_wait = 30
|
||||||
|
|
||||||
file_path = "$TESTCASE_FILE"
|
file_path = "$TESTCASE_FILE"
|
||||||
locust_tests = prepare_locust_tests(file_path)
|
tests = prepare_locust_tests(file_path)
|
||||||
functions = locust_tests["functions"]
|
|
||||||
tests = locust_tests["tests"]
|
|
||||||
config = {}
|
|
||||||
|
|
||||||
host = config.get('base_url', '')
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ def get_os_environ(variable_name):
|
|||||||
|
|
||||||
|
|
||||||
def build_url(base_url, path):
|
def build_url(base_url, path):
|
||||||
""" prepend url with hostname unless it's already an absolute URL """
|
""" prepend url with base_url unless it's already an absolute URL """
|
||||||
if absolute_http_url_regexp.match(path):
|
if absolute_http_url_regexp.match(path):
|
||||||
return path
|
return path
|
||||||
elif base_url:
|
elif base_url:
|
||||||
@@ -120,39 +120,6 @@ def query_json(json_content, query, delimiter='.'):
|
|||||||
return json_content
|
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):
|
def deep_update_dict(origin_dict, override_dict):
|
||||||
""" update origin dict with override dict recursively
|
""" update origin dict with override dict recursively
|
||||||
e.g. origin_dict = {'a': 1, 'b': {'c': 2, 'd': 4}}
|
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!")
|
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):
|
def extend_variables(raw_variables, override_variables):
|
||||||
""" extend raw_variables with override_variables.
|
""" extend raw_variables with override_variables.
|
||||||
override_variables will merge and override raw_variables.
|
override_variables will merge and override raw_variables.
|
||||||
@@ -581,25 +476,6 @@ def gen_cartesian_product(*args):
|
|||||||
return product_list
|
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):
|
def prettify_json_file(file_list):
|
||||||
""" prettify JSON testcase format
|
""" prettify JSON testcase format
|
||||||
"""
|
"""
|
||||||
@@ -649,6 +525,13 @@ def omit_long_data(body, omit_len=512):
|
|||||||
def dump_json_file(json_data, pwd_dir_path, dump_file_name):
|
def dump_json_file(json_data, pwd_dir_path, dump_file_name):
|
||||||
""" dump json data to file
|
""" dump json data to file
|
||||||
"""
|
"""
|
||||||
|
class PythonObjectEncoder(json.JSONEncoder):
|
||||||
|
def default(self, obj):
|
||||||
|
try:
|
||||||
|
return super().default(self, obj)
|
||||||
|
except TypeError:
|
||||||
|
return str(obj)
|
||||||
|
|
||||||
logs_dir_path = os.path.join(pwd_dir_path, "logs")
|
logs_dir_path = os.path.join(pwd_dir_path, "logs")
|
||||||
if not os.path.isdir(logs_dir_path):
|
if not os.path.isdir(logs_dir_path):
|
||||||
os.makedirs(logs_dir_path)
|
os.makedirs(logs_dir_path)
|
||||||
@@ -663,7 +546,8 @@ def dump_json_file(json_data, pwd_dir_path, dump_file_name):
|
|||||||
json_data,
|
json_data,
|
||||||
indent=4,
|
indent=4,
|
||||||
separators=(',', ':'),
|
separators=(',', ':'),
|
||||||
ensure_ascii=False
|
ensure_ascii=False,
|
||||||
|
cls=PythonObjectEncoder
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -672,14 +556,15 @@ def dump_json_file(json_data, pwd_dir_path, dump_file_name):
|
|||||||
outfile,
|
outfile,
|
||||||
indent=4,
|
indent=4,
|
||||||
separators=(',', ':'),
|
separators=(',', ':'),
|
||||||
ensure_ascii=False
|
ensure_ascii=False,
|
||||||
|
cls=PythonObjectEncoder
|
||||||
)
|
)
|
||||||
|
|
||||||
msg = "dump file: {}".format(dump_file_path)
|
msg = "dump file: {}".format(dump_file_path)
|
||||||
logger.color_print(msg, "BLUE")
|
logger.color_print(msg, "BLUE")
|
||||||
|
|
||||||
except TypeError:
|
except TypeError as ex:
|
||||||
msg = "Failed to dump json file: {}".format(dump_file_path)
|
msg = "Failed to dump json file: {}\nReason: {}".format(dump_file_path, ex)
|
||||||
logger.color_print(msg, "RED")
|
logger.color_print(msg, "RED")
|
||||||
|
|
||||||
|
|
||||||
@@ -694,47 +579,18 @@ def _prepare_dump_info(project_mapping, tag_name):
|
|||||||
return pwd_dir_path, dump_file_name
|
return pwd_dir_path, dump_file_name
|
||||||
|
|
||||||
|
|
||||||
def dump_tests(tests_mapping, tag_name):
|
def dump_logs(json_data, project_mapping, tag_name):
|
||||||
""" dump loaded/parsed tests data (except functions) to json file.
|
""" dump tests data to json file.
|
||||||
the dumped file is located in PWD/logs folder.
|
the dumped file is located in PWD/logs folder.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
tests_mapping (dict): data to dump
|
json_data (list/dict): json data to dump
|
||||||
tag_name (str): tag name, loaded/parsed
|
project_mapping (dict): project info
|
||||||
|
tag_name (str): tag name, loaded/parsed/summary
|
||||||
|
|
||||||
"""
|
"""
|
||||||
project_mapping = tests_mapping.get("project_mapping", {})
|
|
||||||
pwd_dir_path, dump_file_name = _prepare_dump_info(project_mapping, tag_name)
|
pwd_dir_path, dump_file_name = _prepare_dump_info(project_mapping, tag_name)
|
||||||
|
dump_json_file(json_data, pwd_dir_path, dump_file_name)
|
||||||
tests_to_dump = {
|
|
||||||
"project_mapping": {}
|
|
||||||
}
|
|
||||||
|
|
||||||
for key in project_mapping:
|
|
||||||
if key != "functions":
|
|
||||||
tests_to_dump["project_mapping"][key] = project_mapping[key]
|
|
||||||
continue
|
|
||||||
|
|
||||||
# remove functions in order to dump
|
|
||||||
if project_mapping["functions"]:
|
|
||||||
debugtalk_py_path = os.path.join(pwd_dir_path, "debugtalk.py")
|
|
||||||
tests_to_dump["project_mapping"]["debugtalk.py"] = debugtalk_py_path
|
|
||||||
|
|
||||||
if "api" in tests_mapping:
|
|
||||||
tests_to_dump["api"] = tests_mapping["api"]
|
|
||||||
elif "testcases" in tests_mapping:
|
|
||||||
tests_to_dump["testcases"] = tests_mapping["testcases"]
|
|
||||||
elif "testsuites" in tests_mapping:
|
|
||||||
tests_to_dump["testsuites"] = tests_mapping["testsuites"]
|
|
||||||
|
|
||||||
dump_json_file(tests_to_dump, pwd_dir_path, dump_file_name)
|
|
||||||
|
|
||||||
|
|
||||||
def dump_summary(summary, project_mapping):
|
|
||||||
""" dump test result summary to json file.
|
|
||||||
"""
|
|
||||||
pwd_dir_path, dump_file_name = _prepare_dump_info(project_mapping, "summary")
|
|
||||||
dump_json_file(summary, pwd_dir_path, dump_file_name)
|
|
||||||
|
|
||||||
|
|
||||||
def get_python2_retire_msg():
|
def get_python2_retire_msg():
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
import collections
|
||||||
|
import io
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import types
|
import types
|
||||||
|
|
||||||
|
from httprunner import exceptions, logger
|
||||||
|
|
||||||
|
|
||||||
""" validate data format
|
""" validate data format
|
||||||
TODO: refactor with JSON schema validate
|
TODO: refactor with JSON schema validate
|
||||||
@@ -129,6 +134,170 @@ def is_testcase_path(path):
|
|||||||
return True
|
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
|
## validate varibles and functions
|
||||||
###############################################################################
|
###############################################################################
|
||||||
@@ -157,3 +326,22 @@ def is_variable(tup):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
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")
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ request:
|
|||||||
Content-Type: "application/json"
|
Content-Type: "application/json"
|
||||||
device_sn: $device_sn
|
device_sn: $device_sn
|
||||||
json:
|
json:
|
||||||
sign: ${get_sign($user_agent, $device_sn, $os_platform, $app_version)}
|
sign: ${get_sign($device_sn, $os_platform, $app_version)}
|
||||||
validate:
|
validate:
|
||||||
- eq: ["status_code", 0]
|
- eq: ["status_code", 0]
|
||||||
- len_eq: ["content.token", 12]
|
- len_eq: ["content.token", 12]
|
||||||
|
|||||||
@@ -93,15 +93,13 @@ def index():
|
|||||||
|
|
||||||
@app.route('/api/get-token', methods=['POST'])
|
@app.route('/api/get-token', methods=['POST'])
|
||||||
def get_token():
|
def get_token():
|
||||||
user_agent = request.headers.get('User-Agent', "")
|
|
||||||
device_sn = request.headers.get('device_sn', "")
|
device_sn = request.headers.get('device_sn', "")
|
||||||
os_platform = request.headers.get('os_platform', "")
|
os_platform = request.headers.get('os_platform', "")
|
||||||
app_version = request.headers.get('app_version', "")
|
app_version = request.headers.get('app_version', "")
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
sign = data.get('sign', "")
|
sign = data.get('sign', "")
|
||||||
|
|
||||||
expected_sign = get_sign(user_agent, device_sn, os_platform, app_version)
|
expected_sign = get_sign(device_sn, os_platform, app_version)
|
||||||
|
|
||||||
if expected_sign != sign:
|
if expected_sign != sign:
|
||||||
result = {
|
result = {
|
||||||
'success': False,
|
'success': False,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class ApiServerUnittest(unittest.TestCase):
|
|||||||
'app_version': app_version
|
'app_version': app_version
|
||||||
}
|
}
|
||||||
data = {
|
data = {
|
||||||
'sign': get_sign(user_agent, device_sn, os_platform, app_version)
|
'sign': get_sign(device_sn, os_platform, app_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp = self.api_client.post(url, json=data, headers=headers)
|
resp = self.api_client.post(url, json=data, headers=headers)
|
||||||
|
|||||||
13
tests/data/bugfix_verify.yml
Normal file
13
tests/data/bugfix_verify.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
- config:
|
||||||
|
name: basic test with httpbin
|
||||||
|
base_url: https://httpbin.org/
|
||||||
|
verify: False
|
||||||
|
|
||||||
|
- test:
|
||||||
|
name: headers
|
||||||
|
request:
|
||||||
|
url: /headers
|
||||||
|
method: GET
|
||||||
|
validate:
|
||||||
|
- eq: ["status_code", 200]
|
||||||
|
- eq: [content.headers.Host, "httpbin.org"]
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
- config:
|
- config:
|
||||||
name: "123$var_a"
|
name: "123t$var_a"
|
||||||
variables:
|
variables:
|
||||||
var_a: 0
|
var_a: 1
|
||||||
var_c: "${sum_two(1, 2)}"
|
var_b: 2
|
||||||
|
var_c: "${sum_two($var_a, $var_b)}"
|
||||||
var_d: "${gen_random_string(5)}"
|
var_d: "${gen_random_string(5)}"
|
||||||
var_e: $var_d
|
var_e: $var_d
|
||||||
PROJECT_KEY: ${ENV(PROJECT_KEY)}
|
PROJECT_KEY: ${ENV(PROJECT_KEY)}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
os_platform: 'ios'
|
os_platform: 'ios'
|
||||||
app_version: '2.8.6'
|
app_version: '2.8.6'
|
||||||
json:
|
json:
|
||||||
sign: f1219719911caae89ccc301679857ebfda115ca2
|
sign: 5188962c489d1a35effa99e9346dd5efd4fdabad
|
||||||
variables:
|
variables:
|
||||||
expect_status_code: 200
|
expect_status_code: 200
|
||||||
token_len: 16
|
token_len: 16
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
os_platform: $os_platform
|
os_platform: $os_platform
|
||||||
app_version: $app_version
|
app_version: $app_version
|
||||||
json:
|
json:
|
||||||
sign: ${get_sign($user_agent, $device_sn, $os_platform, $app_version)}
|
sign: ${get_sign($device_sn, $os_platform, $app_version)}
|
||||||
extract:
|
extract:
|
||||||
- token: content.token
|
- token: content.token
|
||||||
validate:
|
validate:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"app_version": "2.8.6"
|
"app_version": "2.8.6"
|
||||||
},
|
},
|
||||||
"json": {
|
"json": {
|
||||||
"sign": "f1219719911caae89ccc301679857ebfda115ca2"
|
"sign": "5188962c489d1a35effa99e9346dd5efd4fdabad"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"variables": [
|
"variables": [
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
os_platform: 'ios'
|
os_platform: 'ios'
|
||||||
app_version: '2.8.6'
|
app_version: '2.8.6'
|
||||||
json:
|
json:
|
||||||
sign: f1219719911caae89ccc301679857ebfda115ca2
|
sign: 5188962c489d1a35effa99e9346dd5efd4fdabad
|
||||||
variables:
|
variables:
|
||||||
expect_status_code: 200
|
expect_status_code: 200
|
||||||
token_len: 16
|
token_len: 16
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
user_agent: 'iOS/10.3'
|
user_agent: 'iOS/10.3'
|
||||||
os_platform: 'ios'
|
os_platform: 'ios'
|
||||||
app_version: '2.8.6'
|
app_version: '2.8.6'
|
||||||
sign: f1219719911caae89ccc301679857ebfda115ca2
|
sign: 5188962c489d1a35effa99e9346dd5efd4fdabad
|
||||||
request:
|
request:
|
||||||
url: /api/get-token
|
url: /api/get-token
|
||||||
method: POST
|
method: POST
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ request:
|
|||||||
url: https://debugtalk.com
|
url: https://debugtalk.com
|
||||||
status_code: 302
|
status_code: 302
|
||||||
method: GET
|
method: GET
|
||||||
|
verify: False
|
||||||
validate:
|
validate:
|
||||||
- eq: ["status_code", 200]
|
- eq: ["status_code", 200]
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ config:
|
|||||||
|
|
||||||
testcases:
|
testcases:
|
||||||
create user 1000 and check result.:
|
create user 1000 and check result.:
|
||||||
testcase: testcases/create_and_check.yml
|
testcase: testcases/create_user.yml
|
||||||
weight: 2
|
weight: 2
|
||||||
variables:
|
variables:
|
||||||
uid: 1000
|
uid: 1000
|
||||||
|
|
||||||
create user 1001 and check result.:
|
create user 1001 and check result.:
|
||||||
testcase: testcases/create_and_check.yml
|
testcase: testcases/create_user.yml
|
||||||
weight: 3
|
weight: 3
|
||||||
variables:
|
variables:
|
||||||
uid: 1001
|
uid: 1001
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class TestHttpRunner(ApiServerUnittest):
|
|||||||
'url': 'http://127.0.0.1:5000/api/get-token',
|
'url': 'http://127.0.0.1:5000/api/get-token',
|
||||||
'method': 'POST',
|
'method': 'POST',
|
||||||
'headers': {'Content-Type': 'application/json', 'app_version': '2.8.6', 'device_sn': 'FwgRiO7CNA50DSU', 'os_platform': 'ios', 'user_agent': 'iOS/10.3'},
|
'headers': {'Content-Type': 'application/json', 'app_version': '2.8.6', 'device_sn': 'FwgRiO7CNA50DSU', 'os_platform': 'ios', 'user_agent': 'iOS/10.3'},
|
||||||
'json': {'sign': '958a05393efef0ac7c0fb80a7eac45e24fd40c27'}
|
'json': {'sign': '9c0c7e51c91ae963c833a4ccbab8d683c4a90c98'}
|
||||||
},
|
},
|
||||||
'extract': [
|
'extract': [
|
||||||
{'token': 'content.token'}
|
{'token': 'content.token'}
|
||||||
@@ -52,7 +52,8 @@ class TestHttpRunner(ApiServerUnittest):
|
|||||||
'request': {
|
'request': {
|
||||||
'url': 'http://127.0.0.1:5000/api/users/1000',
|
'url': 'http://127.0.0.1:5000/api/users/1000',
|
||||||
'method': 'POST',
|
'method': 'POST',
|
||||||
'headers': {'Content-Type': 'application/json', 'device_sn': 'FwgRiO7CNA50DSU','token': '$token'}, 'json': {'name': 'user1', 'password': '123456'}
|
'headers': {'Content-Type': 'application/json', 'device_sn': 'FwgRiO7CNA50DSU','token': '$token'},
|
||||||
|
'json': {'name': 'user1', 'password': '123456'}
|
||||||
},
|
},
|
||||||
'validate': [
|
'validate': [
|
||||||
{'eq': ['status_code', 201]},
|
{'eq': ['status_code', 201]},
|
||||||
@@ -137,11 +138,11 @@ class TestHttpRunner(ApiServerUnittest):
|
|||||||
self.assertEqual(len(vars_out), 6)
|
self.assertEqual(len(vars_out), 6)
|
||||||
self.assertEqual(vars_out[0]["in"]["uid"], 101)
|
self.assertEqual(vars_out[0]["in"]["uid"], 101)
|
||||||
self.assertEqual(vars_out[0]["in"]["device_sn"], "TESTSUITE_X1")
|
self.assertEqual(vars_out[0]["in"]["device_sn"], "TESTSUITE_X1")
|
||||||
token1 = vars_out[0]["out"]["token"]
|
token1 = vars_out[0]["out"]["session_token"]
|
||||||
self.assertEqual(len(token1), 16)
|
self.assertEqual(len(token1), 16)
|
||||||
self.assertEqual(vars_out[5]["in"]["uid"], 103)
|
self.assertEqual(vars_out[5]["in"]["uid"], 103)
|
||||||
self.assertEqual(vars_out[5]["in"]["device_sn"], "TESTSUITE_X2")
|
self.assertEqual(vars_out[5]["in"]["device_sn"], "TESTSUITE_X2")
|
||||||
token2 = vars_out[0]["out"]["token"]
|
token2 = vars_out[0]["out"]["session_token"]
|
||||||
self.assertEqual(len(token2), 16)
|
self.assertEqual(len(token2), 16)
|
||||||
self.assertEqual(token1, token2)
|
self.assertEqual(token1, token2)
|
||||||
|
|
||||||
@@ -240,7 +241,7 @@ class TestHttpRunner(ApiServerUnittest):
|
|||||||
summary = self.runner.summary
|
summary = self.runner.summary
|
||||||
self.assertTrue(summary["success"])
|
self.assertTrue(summary["success"])
|
||||||
self.assertEqual(summary["stat"]["testcases"]["total"], 2)
|
self.assertEqual(summary["stat"]["testcases"]["total"], 2)
|
||||||
self.assertEqual(summary["stat"]["teststeps"]["total"], 8)
|
self.assertEqual(summary["stat"]["teststeps"]["total"], 4)
|
||||||
|
|
||||||
def test_run_httprunner_with_hooks(self):
|
def test_run_httprunner_with_hooks(self):
|
||||||
testcase_file_path = os.path.join(
|
testcase_file_path = os.path.join(
|
||||||
@@ -470,7 +471,7 @@ class TestHttpRunner(ApiServerUnittest):
|
|||||||
self.assertEqual(len(summary["details"]), 3 * 2)
|
self.assertEqual(len(summary["details"]), 3 * 2)
|
||||||
|
|
||||||
self.assertEqual(summary["stat"]["testcases"]["total"], 6)
|
self.assertEqual(summary["stat"]["testcases"]["total"], 6)
|
||||||
self.assertEqual(summary["stat"]["teststeps"]["total"], 3 * 2 * 4)
|
self.assertEqual(summary["stat"]["teststeps"]["total"], 3 * 2 * 2)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
summary["details"][0]["name"],
|
summary["details"][0]["name"],
|
||||||
"create user 101 and check result for TESTSUITE_X1."
|
"create user 101 and check result for TESTSUITE_X1."
|
||||||
@@ -481,10 +482,10 @@ class TestHttpRunner(ApiServerUnittest):
|
|||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
summary["details"][0]["stat"]["total"],
|
summary["details"][0]["stat"]["total"],
|
||||||
4
|
2
|
||||||
)
|
)
|
||||||
records_name_list = [
|
records_name_list = [
|
||||||
summary["details"][i]["records"][2]["name"]
|
summary["details"][i]["records"][1]["meta_datas"][1]["name"]
|
||||||
for i in range(6)
|
for i in range(6)
|
||||||
]
|
]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -577,8 +578,7 @@ class TestApi(ApiServerUnittest):
|
|||||||
testcase_path = "tests/testcases/setup.yml"
|
testcase_path = "tests/testcases/setup.yml"
|
||||||
tests_mapping = loader.load_tests(testcase_path)
|
tests_mapping = loader.load_tests(testcase_path)
|
||||||
|
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
parsed_testcases = parsed_tests_mapping["testcases"]
|
|
||||||
|
|
||||||
self.assertEqual(len(parsed_testcases), 1)
|
self.assertEqual(len(parsed_testcases), 1)
|
||||||
|
|
||||||
@@ -589,7 +589,7 @@ class TestApi(ApiServerUnittest):
|
|||||||
self.assertEqual(test_dict1["name"], "get token (setup)")
|
self.assertEqual(test_dict1["name"], "get token (setup)")
|
||||||
self.assertNotIn("api_def", test_dict1)
|
self.assertNotIn("api_def", test_dict1)
|
||||||
self.assertEqual(test_dict1["variables"]["device_sn"], "TESTCASE_SETUP_XXX")
|
self.assertEqual(test_dict1["variables"]["device_sn"], "TESTCASE_SETUP_XXX")
|
||||||
self.assertEqual(test_dict1["request"]["url"], "http://127.0.0.1:5000/api/get-token")
|
self.assertEqual(test_dict1["request"]["url"], "/api/get-token")
|
||||||
self.assertEqual(test_dict1["request"]["verify"], False)
|
self.assertEqual(test_dict1["request"]["verify"], False)
|
||||||
|
|
||||||
test_dict2 = parsed_testcases[0]["teststeps"][1]
|
test_dict2 = parsed_testcases[0]["teststeps"][1]
|
||||||
@@ -599,9 +599,9 @@ class TestApi(ApiServerUnittest):
|
|||||||
testcase_path = "tests/testcases/setup.yml"
|
testcase_path = "tests/testcases/setup.yml"
|
||||||
tests_mapping = loader.load_tests(testcase_path)
|
tests_mapping = loader.load_tests(testcase_path)
|
||||||
|
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
testcases = parser.parse_tests(tests_mapping)
|
||||||
runner = HttpRunner()
|
runner = HttpRunner()
|
||||||
test_suite = runner._add_tests(parsed_tests_mapping)
|
test_suite = runner._add_tests(testcases)
|
||||||
|
|
||||||
self.assertEqual(len(test_suite._tests), 1)
|
self.assertEqual(len(test_suite._tests), 1)
|
||||||
teststeps = test_suite._tests[0].teststeps
|
teststeps = test_suite._tests[0].teststeps
|
||||||
@@ -610,38 +610,39 @@ class TestApi(ApiServerUnittest):
|
|||||||
self.assertIn("api", teststeps[0])
|
self.assertIn("api", teststeps[0])
|
||||||
|
|
||||||
def test_testcase_complex_verify(self):
|
def test_testcase_complex_verify(self):
|
||||||
testcase_path = "tests/testcases/create_and_check.yml"
|
testcase_path = "tests/testcases/create_user.yml"
|
||||||
tests_mapping = loader.load_tests(testcase_path)
|
tests_mapping = loader.load_tests(testcase_path)
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
testcases = parser.parse_tests(tests_mapping)
|
||||||
teststeps = parsed_tests_mapping["testcases"][0]["teststeps"]
|
teststeps = testcases[0]["teststeps"]
|
||||||
|
|
||||||
# testcases/setup.yml
|
# testcases/setup.yml
|
||||||
teststep1 = teststeps[0]
|
teststep0 = teststeps[0]
|
||||||
self.assertEqual(teststep1["teststeps"][0]["request"]["verify"], False)
|
self.assertEqual(teststep0["teststeps"][0]["request"]["verify"], False)
|
||||||
self.assertEqual(teststep1["teststeps"][1]["request"]["verify"], False)
|
self.assertEqual(teststep0["teststeps"][1]["request"]["verify"], False)
|
||||||
|
|
||||||
# testcases/create_and_check.yml teststep 2/3/4
|
# testcases/create_user.yml
|
||||||
self.assertEqual(teststeps[1]["request"]["verify"], True)
|
teststep1 = teststeps[1]
|
||||||
self.assertEqual(teststeps[2]["request"]["verify"], True)
|
self.assertEqual(teststep1["teststeps"][0]["request"]["verify"], True)
|
||||||
self.assertEqual(teststeps[3]["request"]["verify"], True)
|
self.assertEqual(teststep1["teststeps"][1]["request"]["verify"], True)
|
||||||
|
self.assertEqual(teststep1["teststeps"][2]["request"]["verify"], True)
|
||||||
|
|
||||||
def test_testcase_simple_run_suite(self):
|
def test_testcase_simple_run_suite(self):
|
||||||
testcase_path = "tests/testcases/setup.yml"
|
testcase_path = "tests/testcases/setup.yml"
|
||||||
tests_mapping = loader.load_tests(testcase_path)
|
tests_mapping = loader.load_tests(testcase_path)
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
testcases = parser.parse_tests(tests_mapping)
|
||||||
runner = HttpRunner()
|
runner = HttpRunner()
|
||||||
test_suite = runner._add_tests(parsed_tests_mapping)
|
test_suite = runner._add_tests(testcases)
|
||||||
tests_results = runner._run_suite(test_suite)
|
tests_results = runner._run_suite(test_suite)
|
||||||
self.assertEqual(len(tests_results[0][1].records), 2)
|
self.assertEqual(len(tests_results[0][1].records), 2)
|
||||||
|
|
||||||
def test_testcase_complex_run_suite(self):
|
def test_testcase_complex_run_suite(self):
|
||||||
testcase_path = "tests/testcases/create_and_check.yml"
|
testcase_path = "tests/testcases/create_user.yml"
|
||||||
tests_mapping = loader.load_tests(testcase_path)
|
tests_mapping = loader.load_tests(testcase_path)
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
testcases = parser.parse_tests(tests_mapping)
|
||||||
runner = HttpRunner()
|
runner = HttpRunner()
|
||||||
test_suite = runner._add_tests(parsed_tests_mapping)
|
test_suite = runner._add_tests(testcases)
|
||||||
tests_results = runner._run_suite(test_suite)
|
tests_results = runner._run_suite(test_suite)
|
||||||
self.assertEqual(len(tests_results[0][1].records), 4)
|
self.assertEqual(len(tests_results[0][1].records), 2)
|
||||||
|
|
||||||
results = tests_results[0][1]
|
results = tests_results[0][1]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -650,7 +651,7 @@ class TestApi(ApiServerUnittest):
|
|||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
results.records[1]["name"],
|
results.records[1]["name"],
|
||||||
"make sure user 9001 does not exist"
|
"create user and check result."
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_testsuite_loader(self):
|
def test_testsuite_loader(self):
|
||||||
@@ -679,7 +680,7 @@ class TestApi(ApiServerUnittest):
|
|||||||
self.assertEqual(testcase_tests["name"], "create user 1000 and check result.")
|
self.assertEqual(testcase_tests["name"], "create user 1000 and check result.")
|
||||||
self.assertIsInstance(testcase_tests["testcase_def"], dict)
|
self.assertIsInstance(testcase_tests["testcase_def"], dict)
|
||||||
self.assertEqual(testcase_tests["testcase_def"]["config"]["name"], "create user and check result.")
|
self.assertEqual(testcase_tests["testcase_def"]["config"]["name"], "create user and check result.")
|
||||||
self.assertEqual(len(testcase_tests["testcase_def"]["teststeps"]), 4)
|
self.assertEqual(len(testcase_tests["testcase_def"]["teststeps"]), 2)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
testcase_tests["testcase_def"]["teststeps"][0]["name"],
|
testcase_tests["testcase_def"]["teststeps"][0]["name"],
|
||||||
"setup and reset all (override) for $device_sn."
|
"setup and reset all (override) for $device_sn."
|
||||||
@@ -689,57 +690,52 @@ class TestApi(ApiServerUnittest):
|
|||||||
testcase_path = "tests/testsuites/create_users.yml"
|
testcase_path = "tests/testsuites/create_users.yml"
|
||||||
tests_mapping = loader.load_tests(testcase_path)
|
tests_mapping = loader.load_tests(testcase_path)
|
||||||
|
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
|
|
||||||
parsed_testcases = parsed_tests_mapping["testcases"]
|
|
||||||
self.assertEqual(len(parsed_testcases), 2)
|
self.assertEqual(len(parsed_testcases), 2)
|
||||||
self.assertEqual(len(parsed_testcases[0]["teststeps"]), 4)
|
self.assertEqual(len(parsed_testcases[0]["teststeps"]), 2)
|
||||||
|
|
||||||
testcase1 = parsed_testcases[0]["teststeps"][0]
|
testcase1 = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertIn("setup and reset all (override)", testcase1["config"]["name"])
|
self.assertIn("setup and reset all (override)", testcase1["config"]["name"].raw_string)
|
||||||
self.assertEqual(testcase1["teststeps"][0]["variables"]["var_c"], testcase1["teststeps"][0]["variables"]["var_d"])
|
teststeps = testcase1["teststeps"]
|
||||||
self.assertEqual(testcase1["teststeps"][0]["variables"]["var_a"], testcase1["teststeps"][0]["variables"]["var_b"])
|
|
||||||
self.assertNotEqual(testcase1["teststeps"][0]["variables"]["var_a"], testcase1["teststeps"][0]["variables"]["var_c"])
|
|
||||||
self.assertNotIn("testcase_def", testcase1)
|
self.assertNotIn("testcase_def", testcase1)
|
||||||
self.assertEqual(len(testcase1["teststeps"]), 2)
|
self.assertEqual(len(teststeps), 2)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
testcase1["teststeps"][0]["request"]["url"],
|
teststeps[0]["request"]["url"],
|
||||||
"http://127.0.0.1:5000/api/get-token"
|
"/api/get-token"
|
||||||
)
|
)
|
||||||
self.assertEqual(len(testcase1["teststeps"][0]["variables"]["device_sn"]), 15)
|
|
||||||
|
|
||||||
def test_testsuite_add_tests(self):
|
def test_testsuite_add_tests(self):
|
||||||
testcase_path = "tests/testsuites/create_users.yml"
|
testcase_path = "tests/testsuites/create_users.yml"
|
||||||
tests_mapping = loader.load_tests(testcase_path)
|
tests_mapping = loader.load_tests(testcase_path)
|
||||||
|
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
testcases = parser.parse_tests(tests_mapping)
|
||||||
runner = HttpRunner()
|
runner = HttpRunner()
|
||||||
test_suite = runner._add_tests(parsed_tests_mapping)
|
test_suite = runner._add_tests(testcases)
|
||||||
|
|
||||||
self.assertEqual(len(test_suite._tests), 2)
|
self.assertEqual(len(test_suite._tests), 2)
|
||||||
tests = test_suite._tests[0].teststeps
|
tests = test_suite._tests[0].teststeps
|
||||||
self.assertIn("setup and reset all (override)", tests[0]["config"]["name"])
|
self.assertIn("setup and reset all (override)", tests[0]["config"]["name"].raw_string)
|
||||||
|
|
||||||
def test_testsuite_run_suite(self):
|
def test_testsuite_run_suite(self):
|
||||||
testcase_path = "tests/testsuites/create_users.yml"
|
testcase_path = "tests/testsuites/create_users.yml"
|
||||||
tests_mapping = loader.load_tests(testcase_path)
|
tests_mapping = loader.load_tests(testcase_path)
|
||||||
|
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
testcases = parser.parse_tests(tests_mapping)
|
||||||
|
|
||||||
runner = HttpRunner()
|
runner = HttpRunner()
|
||||||
test_suite = runner._add_tests(parsed_tests_mapping)
|
test_suite = runner._add_tests(testcases)
|
||||||
tests_results = runner._run_suite(test_suite)
|
tests_results = runner._run_suite(test_suite)
|
||||||
|
|
||||||
self.assertEqual(len(tests_results[0][1].records), 4)
|
self.assertEqual(len(tests_results[0][1].records), 2)
|
||||||
|
|
||||||
results = tests_results[0][1]
|
results = tests_results[0][1]
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
"setup and reset all (override)",
|
"setup and reset all (override)",
|
||||||
results.records[0]["name"]
|
results.records[0]["name"]
|
||||||
)
|
)
|
||||||
self.assertIn(
|
self.assertEqual(
|
||||||
results.records[1]["name"],
|
results.records[1]["name"],
|
||||||
["make sure user 1000 does not exist", "make sure user 1001 does not exist"]
|
"create user and check result."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -749,11 +745,10 @@ class TestLocust(unittest.TestCase):
|
|||||||
path = os.path.join(
|
path = os.path.join(
|
||||||
os.getcwd(), 'tests/locust_tests/demo_locusts.yml')
|
os.getcwd(), 'tests/locust_tests/demo_locusts.yml')
|
||||||
locust_tests = prepare_locust_tests(path)
|
locust_tests = prepare_locust_tests(path)
|
||||||
self.assertIn("gen_md5", locust_tests["functions"])
|
self.assertEqual(len(locust_tests), 2 + 3)
|
||||||
self.assertEqual(len(locust_tests["tests"]), 2 + 3)
|
|
||||||
name_list = [
|
name_list = [
|
||||||
"create user 1000 and check result.",
|
"create user 1000 and check result.",
|
||||||
"create user 1001 and check result."
|
"create user 1001 and check result."
|
||||||
]
|
]
|
||||||
self.assertIn(locust_tests["tests"][0]["config"]["name"], name_list)
|
self.assertIn(locust_tests[0]["config"]["name"], name_list)
|
||||||
self.assertIn(locust_tests["tests"][4]["config"]["name"], name_list)
|
self.assertIn(locust_tests[4]["config"]["name"], name_list)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from tests.base import ApiServerUnittest
|
|||||||
class TestHttpClient(ApiServerUnittest):
|
class TestHttpClient(ApiServerUnittest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestHttpClient, self).setUp()
|
super(TestHttpClient, self).setUp()
|
||||||
self.api_client = HttpSession(self.host)
|
self.api_client = HttpSession()
|
||||||
self.headers = self.get_authenticated_headers()
|
self.headers = self.get_authenticated_headers()
|
||||||
self.reset_all()
|
self.reset_all()
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ class TestHttpClient(ApiServerUnittest):
|
|||||||
self.assertEqual(True, resp.json()['success'])
|
self.assertEqual(True, resp.json()['success'])
|
||||||
|
|
||||||
def test_request_without_base_url(self):
|
def test_request_without_base_url(self):
|
||||||
url = "/api/users/1000"
|
url = "{}/api/users/1000".format(self.host)
|
||||||
data = {
|
data = {
|
||||||
'name': 'user1',
|
'name': 'user1',
|
||||||
'password': '123456'
|
'password': '123456'
|
||||||
@@ -40,7 +40,7 @@ class TestHttpClient(ApiServerUnittest):
|
|||||||
self.assertEqual(True, resp.json()['success'])
|
self.assertEqual(True, resp.json()['success'])
|
||||||
|
|
||||||
def test_request_post_data(self):
|
def test_request_post_data(self):
|
||||||
url = "/api/users/1000"
|
url = "{}/api/users/1000".format(self.host)
|
||||||
data = {
|
data = {
|
||||||
'name': 'user1',
|
'name': 'user1',
|
||||||
'password': '123456'
|
'password': '123456'
|
||||||
@@ -56,7 +56,7 @@ class TestHttpClient(ApiServerUnittest):
|
|||||||
self.assertIn("password=123456", resp.request.body)
|
self.assertIn("password=123456", resp.request.body)
|
||||||
|
|
||||||
def test_request_with_cookies(self):
|
def test_request_with_cookies(self):
|
||||||
url = "/api/users/1000"
|
url = "{}/api/users/1000".format(self.host)
|
||||||
data = {
|
data = {
|
||||||
'name': 'user1',
|
'name': 'user1',
|
||||||
'password': '123456'
|
'password': '123456'
|
||||||
@@ -76,7 +76,7 @@ class TestHttpClient(ApiServerUnittest):
|
|||||||
"a": "1",
|
"a": "1",
|
||||||
"b": "2"
|
"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
|
raw_request = resp.history[0].request
|
||||||
self.assertEqual(raw_request._cookies["a"], "1")
|
self.assertEqual(raw_request._cookies["a"], "1")
|
||||||
self.assertEqual(raw_request._cookies["b"], "2")
|
self.assertEqual(raw_request._cookies["b"], "2")
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import requests
|
from httprunner import context, exceptions, loader, parser, runner
|
||||||
from httprunner import context, exceptions, loader, response, utils
|
from tests.base import ApiServerUnittest, gen_md5, gen_random_string
|
||||||
from tests.base import ApiServerUnittest
|
|
||||||
|
|
||||||
|
|
||||||
class TestContext(ApiServerUnittest):
|
class TestContext(ApiServerUnittest):
|
||||||
@@ -12,14 +11,9 @@ class TestContext(ApiServerUnittest):
|
|||||||
loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
|
loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
|
||||||
project_mapping = loader.project_mapping
|
project_mapping = loader.project_mapping
|
||||||
self.context = context.SessionContext(
|
self.context = context.SessionContext(
|
||||||
functions=project_mapping["functions"],
|
|
||||||
variables={"SECRET_KEY": "DebugTalk"}
|
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):
|
def test_init_test_variables_initialize(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.context.test_variables_mapping,
|
self.context.test_variables_mapping,
|
||||||
@@ -30,16 +24,24 @@ class TestContext(ApiServerUnittest):
|
|||||||
variables = {
|
variables = {
|
||||||
"random": "${gen_random_string($num)}",
|
"random": "${gen_random_string($num)}",
|
||||||
"authorization": "${gen_md5($TOKEN, $data, $random)}",
|
"authorization": "${gen_md5($TOKEN, $data, $random)}",
|
||||||
"data": '{"name": "$username", "password": "123456"}',
|
"data": "$username",
|
||||||
|
# TODO: escape '{' and '}'
|
||||||
|
# "data": '{"name": "$username", "password": "123456"}',
|
||||||
"TOKEN": "debugtalk",
|
"TOKEN": "debugtalk",
|
||||||
"username": "user1",
|
"username": "user1",
|
||||||
"num": 6
|
"num": 6
|
||||||
}
|
}
|
||||||
|
functions = {
|
||||||
|
"gen_random_string": gen_random_string,
|
||||||
|
"gen_md5": gen_md5
|
||||||
|
}
|
||||||
|
variables = parser.prepare_lazy_data(variables, functions, variables.keys())
|
||||||
|
variables = parser.parse_variables_mapping(variables)
|
||||||
self.context.init_test_variables(variables)
|
self.context.init_test_variables(variables)
|
||||||
variables_mapping = self.context.test_variables_mapping
|
variables_mapping = self.context.test_variables_mapping
|
||||||
self.assertEqual(len(variables_mapping["random"]), 6)
|
self.assertEqual(len(variables_mapping["random"]), 6)
|
||||||
self.assertEqual(len(variables_mapping["authorization"]), 32)
|
self.assertEqual(len(variables_mapping["authorization"]), 32)
|
||||||
self.assertEqual(variables_mapping["data"], '{"name": "user1", "password": "123456"}')
|
self.assertEqual(variables_mapping["data"], 'user1')
|
||||||
|
|
||||||
def test_update_seesion_variables(self):
|
def test_update_seesion_variables(self):
|
||||||
self.context.update_session_variables({"TOKEN": "debugtalk"})
|
self.context.update_session_variables({"TOKEN": "debugtalk"})
|
||||||
@@ -48,15 +50,11 @@ class TestContext(ApiServerUnittest):
|
|||||||
"debugtalk"
|
"debugtalk"
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_eval_content_functions(self):
|
|
||||||
content = "${sleep_N_secs(1)}"
|
|
||||||
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):
|
def test_eval_content_variables(self):
|
||||||
content = "abc$SECRET_KEY"
|
variables = {
|
||||||
|
"SECRET_KEY": "DebugTalk"
|
||||||
|
}
|
||||||
|
content = parser.prepare_lazy_data("abc$SECRET_KEY", {}, variables.keys())
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.context.eval_content(content),
|
self.context.eval_content(content),
|
||||||
"abcDebugTalk"
|
"abcDebugTalk"
|
||||||
@@ -76,7 +74,12 @@ class TestContext(ApiServerUnittest):
|
|||||||
"authorization": "${gen_md5($TOKEN, $data, $random)}",
|
"authorization": "${gen_md5($TOKEN, $data, $random)}",
|
||||||
"TOKEN": "debugtalk"
|
"TOKEN": "debugtalk"
|
||||||
}
|
}
|
||||||
|
functions = {
|
||||||
|
"gen_random_string": gen_random_string,
|
||||||
|
"gen_md5": gen_md5
|
||||||
|
}
|
||||||
|
variables = parser.prepare_lazy_data(variables, functions, variables.keys())
|
||||||
|
variables = parser.parse_variables_mapping(variables)
|
||||||
self.context.init_test_variables(variables)
|
self.context.init_test_variables(variables)
|
||||||
|
|
||||||
request = {
|
request = {
|
||||||
@@ -90,7 +93,12 @@ class TestContext(ApiServerUnittest):
|
|||||||
},
|
},
|
||||||
"data": "$data"
|
"data": "$data"
|
||||||
}
|
}
|
||||||
parsed_request = self.context.eval_content(request)
|
prepared_request = parser.prepare_lazy_data(
|
||||||
|
request,
|
||||||
|
functions,
|
||||||
|
{"authorization", "random", "SECRET_KEY", "data"}
|
||||||
|
)
|
||||||
|
parsed_request = self.context.eval_content(prepared_request)
|
||||||
self.assertIn("authorization", parsed_request["headers"])
|
self.assertIn("authorization", parsed_request["headers"])
|
||||||
self.assertEqual(len(parsed_request["headers"]["authorization"]), 32)
|
self.assertEqual(len(parsed_request["headers"]["authorization"]), 32)
|
||||||
self.assertIn("random", parsed_request["headers"])
|
self.assertIn("random", parsed_request["headers"])
|
||||||
@@ -102,74 +110,80 @@ class TestContext(ApiServerUnittest):
|
|||||||
)
|
)
|
||||||
self.assertEqual(parsed_request["headers"]["secret_key"], "DebugTalk")
|
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):
|
def test_validate(self):
|
||||||
url = "http://127.0.0.1:5000/"
|
testcases = [
|
||||||
resp = requests.get(url)
|
{
|
||||||
resp_obj = response.ResponseObject(resp)
|
"config": {
|
||||||
|
'name': "test validation"
|
||||||
validators = [
|
},
|
||||||
{"eq": ["$resp_status_code", 201]},
|
"teststeps": [
|
||||||
{"check": "$resp_status_code", "comparator": "eq", "expect": 201},
|
{
|
||||||
{"check": "$resp_body_success", "comparator": "eq", "expect": True}
|
"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}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
variables = {
|
from tests.debugtalk import is_status_code_200
|
||||||
"resp_status_code": 200,
|
tests_mapping = {
|
||||||
"resp_body_success": True
|
"project_mapping": {
|
||||||
|
"functions": {
|
||||||
|
"is_status_code_200": is_status_code_200
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"testcases": testcases
|
||||||
}
|
}
|
||||||
|
testcases = parser.parse_tests(tests_mapping)
|
||||||
self.context.init_test_variables(variables)
|
parsed_testcase = testcases[0]
|
||||||
|
test_runner = runner.Runner(parsed_testcase["config"])
|
||||||
with self.assertRaises(exceptions.ValidationFailure):
|
teststep = parsed_testcase["teststeps"][0]
|
||||||
self.context.validate(validators, resp_obj)
|
test_runner.run_test(teststep)
|
||||||
|
|
||||||
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}
|
|
||||||
]
|
|
||||||
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, [])
|
|
||||||
|
|
||||||
def test_validate_exception(self):
|
def test_validate_exception(self):
|
||||||
url = "http://127.0.0.1:5000/"
|
testcases = [
|
||||||
resp = requests.get(url)
|
{
|
||||||
resp_obj = response.ResponseObject(resp)
|
"config": {
|
||||||
|
'name': "test validation"
|
||||||
# expected value missed in validators
|
},
|
||||||
validators = [
|
"teststeps": [
|
||||||
{"eq": ["$resp_status_code", 201]},
|
{
|
||||||
{"check": "$resp_status_code", "comparator": "eq", "expect": 201}
|
"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}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
variables = []
|
tests_mapping = {
|
||||||
self.context.init_test_variables(variables)
|
"testcases": testcases
|
||||||
|
}
|
||||||
with self.assertRaises(exceptions.VariableNotFound):
|
testcases = parser.parse_tests(tests_mapping)
|
||||||
self.context.validate(validators, resp_obj)
|
parsed_testcase = testcases[0]
|
||||||
|
test_runner = runner.Runner(parsed_testcase["config"])
|
||||||
# expected value missed in variables mapping
|
teststep = parsed_testcase["teststeps"][0]
|
||||||
variables = [
|
|
||||||
{"resp_status_code": 200}
|
|
||||||
]
|
|
||||||
self.context.init_test_variables(variables)
|
|
||||||
|
|
||||||
with self.assertRaises(exceptions.ValidationFailure):
|
with self.assertRaises(exceptions.ValidationFailure):
|
||||||
self.context.validate(validators, resp_obj)
|
test_runner.run_test(teststep)
|
||||||
|
|||||||
@@ -348,14 +348,14 @@ class TestSuiteLoader(unittest.TestCase):
|
|||||||
tests_mapping = loader.load_tests(testcase_file_path)
|
tests_mapping = loader.load_tests(testcase_file_path)
|
||||||
testcases = tests_mapping["testcases"]
|
testcases = tests_mapping["testcases"]
|
||||||
self.assertIsInstance(testcases, list)
|
self.assertIsInstance(testcases, list)
|
||||||
self.assertEqual(testcases[0]["config"]["name"], '123$var_a')
|
self.assertEqual(testcases[0]["config"]["name"], '123t$var_a')
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
"sum_two",
|
"sum_two",
|
||||||
tests_mapping["project_mapping"]["functions"]
|
tests_mapping["project_mapping"]["functions"]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
testcases[0]["config"]["variables"]["var_c"],
|
testcases[0]["config"]["variables"]["var_c"],
|
||||||
"${sum_two(1, 2)}"
|
"${sum_two($var_a, $var_b)}"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
testcases[0]["config"]["variables"]["PROJECT_KEY"],
|
testcases[0]["config"]["variables"]["PROJECT_KEY"],
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from httprunner import exceptions, loader, parser
|
from httprunner import exceptions, loader, parser
|
||||||
|
from tests.debugtalk import gen_random_string, sum_two
|
||||||
|
|
||||||
|
|
||||||
class TestParser(unittest.TestCase):
|
class TestParserBasic(unittest.TestCase):
|
||||||
|
|
||||||
def test_parse_string_value(self):
|
def test_parse_string_value(self):
|
||||||
self.assertEqual(parser.parse_string_value("123"), 123)
|
self.assertEqual(parser.parse_string_value("123"), 123)
|
||||||
@@ -14,139 +16,170 @@ class TestParser(unittest.TestCase):
|
|||||||
self.assertEqual(parser.parse_string_value("$var"), "$var")
|
self.assertEqual(parser.parse_string_value("$var"), "$var")
|
||||||
self.assertEqual(parser.parse_string_value("${func}"), "${func}")
|
self.assertEqual(parser.parse_string_value("${func}"), "${func}")
|
||||||
|
|
||||||
def test_extract_variables(self):
|
def test_regex_findall_variables(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("$var"),
|
parser.regex_findall_variables("$var"),
|
||||||
["var"]
|
["var"]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("$var123"),
|
parser.regex_findall_variables("$var123"),
|
||||||
["var123"]
|
["var123"]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("$var_name"),
|
parser.regex_findall_variables("$var_name"),
|
||||||
["var_name"]
|
["var_name"]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("var"),
|
parser.regex_findall_variables("var"),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("a$var"),
|
parser.regex_findall_variables("a$var"),
|
||||||
["var"]
|
["var"]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("$v ar"),
|
parser.regex_findall_variables("$v ar"),
|
||||||
["v"]
|
["v"]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables(" "),
|
parser.regex_findall_variables(" "),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("$abc*"),
|
parser.regex_findall_variables("$abc*"),
|
||||||
["abc"]
|
["abc"]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("${func()}"),
|
parser.regex_findall_variables("${func()}"),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("${func(1,2)}"),
|
parser.regex_findall_variables("${func(1,2)}"),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_variables("${gen_md5($TOKEN, $data, $random)}"),
|
parser.regex_findall_variables("${gen_md5($TOKEN, $data, $random)}"),
|
||||||
["TOKEN", "data", "random"]
|
["TOKEN", "data", "random"]
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_function(self):
|
def test_parse_function_params(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func()"),
|
parser.parse_function_params(""),
|
||||||
{'func_name': 'func', 'args': [], 'kwargs': {}}
|
{'args': [], 'kwargs': {}}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func(5)"),
|
parser.parse_function_params("5"),
|
||||||
{'func_name': 'func', 'args': [5], 'kwargs': {}}
|
{'args': [5], 'kwargs': {}}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func(1, 2)"),
|
parser.parse_function_params("1, 2"),
|
||||||
{'func_name': 'func', 'args': [1, 2], 'kwargs': {}}
|
{'args': [1, 2], 'kwargs': {}}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func(a=1, b=2)"),
|
parser.parse_function_params("a=1, b=2"),
|
||||||
{'func_name': 'func', 'args': [], 'kwargs': {'a': 1, 'b': 2}}
|
{'args': [], 'kwargs': {'a': 1, 'b': 2}}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func(a= 1, b =2)"),
|
parser.parse_function_params("a= 1, b =2"),
|
||||||
{'func_name': 'func', 'args': [], 'kwargs': {'a': 1, 'b': 2}}
|
{'args': [], 'kwargs': {'a': 1, 'b': 2}}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func(1, 2, a=3, b=4)"),
|
parser.parse_function_params("1, 2, a=3, b=4"),
|
||||||
{'func_name': 'func', 'args': [1, 2], 'kwargs': {'a': 3, 'b': 4}}
|
{'args': [1, 2], 'kwargs': {'a': 3, 'b': 4}}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func($request, 123)"),
|
parser.parse_function_params("$request, 123"),
|
||||||
{'func_name': 'func', 'args': ["$request", 123], 'kwargs': {}}
|
{'args': ["$request", 123], 'kwargs': {}}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func( )"),
|
parser.parse_function_params(" "),
|
||||||
{'func_name': 'func', 'args': [], 'kwargs': {}}
|
{'args': [], 'kwargs': {}}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func(hello world, a=3, b=4)"),
|
parser.parse_function_params("hello world, a=3, b=4"),
|
||||||
{'func_name': 'func', 'args': ["hello world"], 'kwargs': {'a': 3, 'b': 4}}
|
{'args': ["hello world"], 'kwargs': {'a': 3, 'b': 4}}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_function("func($request, 12 3)"),
|
parser.parse_function_params("$request, 12 3"),
|
||||||
{'func_name': 'func', 'args': ["$request", '12 3'], 'kwargs': {}}
|
{'args': ["$request", '12 3'], 'kwargs': {}}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_validator(self):
|
def test_extract_variables(self):
|
||||||
validator = {"check": "status_code", "comparator": "eq", "expect": 201}
|
prepared_content = parser.prepare_lazy_data("123$a", {}, {"a"})
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_validator(validator),
|
parser.extract_variables(prepared_content),
|
||||||
{"check": "status_code", "comparator": "eq", "expect": 201}
|
{"a"}
|
||||||
)
|
)
|
||||||
|
prepared_content = parser.prepare_lazy_data("$a$b", {}, {"a", "b"})
|
||||||
validator = {'eq': ['status_code', 201]}
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_validator(validator),
|
parser.extract_variables(prepared_content),
|
||||||
{"check": "status_code", "comparator": "eq", "expect": 201}
|
{"a", "b"}
|
||||||
|
)
|
||||||
|
prepared_content = parser.prepare_lazy_data(["$a$b", "$c", "d"], {}, {"a", "b", "c", "d"})
|
||||||
|
self.assertEqual(
|
||||||
|
parser.extract_variables(prepared_content),
|
||||||
|
{"a", "b", "c"}
|
||||||
|
)
|
||||||
|
prepared_content = parser.prepare_lazy_data(
|
||||||
|
{"a": 1, "b": {"c": "$d", "e": 3}},
|
||||||
|
{},
|
||||||
|
{"d"}
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
parser.extract_variables(prepared_content),
|
||||||
|
{"d"}
|
||||||
|
)
|
||||||
|
prepared_content = parser.prepare_lazy_data(
|
||||||
|
{"a": ["$b"], "b": {"c": "$d", "e": 3}},
|
||||||
|
{},
|
||||||
|
{"b", "d"}
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
parser.extract_variables(prepared_content),
|
||||||
|
{"b", "d"}
|
||||||
|
)
|
||||||
|
prepared_content = parser.prepare_lazy_data(
|
||||||
|
["$a$b", "$c", {"c": "$d"}],
|
||||||
|
{},
|
||||||
|
{"a", "b", "c", "d"}
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
parser.extract_variables(prepared_content),
|
||||||
|
{"a", "b", "c", "d"}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_extract_functions(self):
|
def test_extract_functions(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_functions("${func()}"),
|
parser.regex_findall_functions("${func()}"),
|
||||||
["func()"]
|
[('func', '')]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_functions("${func(5)}"),
|
parser.regex_findall_functions("${func(5)}"),
|
||||||
["func(5)"]
|
[('func', '5')]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_functions("${func(a=1, b=2)}"),
|
parser.regex_findall_functions("${func(a=1, b=2)}"),
|
||||||
["func(a=1, b=2)"]
|
[('func', 'a=1, b=2')]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_functions("${func(1, $b, c=$x, d=4)}"),
|
parser.regex_findall_functions("${func(1, $b, c=$x, d=4)}"),
|
||||||
["func(1, $b, c=$x, d=4)"]
|
[('func', '1, $b, c=$x, d=4')]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_functions("/api/1000?_t=${get_timestamp()}"),
|
parser.regex_findall_functions("/api/1000?_t=${get_timestamp()}"),
|
||||||
["get_timestamp()"]
|
[('get_timestamp', '')]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_functions("/api/${add(1, 2)}"),
|
parser.regex_findall_functions("/api/${add(1, 2)}"),
|
||||||
["add(1, 2)"]
|
[('add', '1, 2')]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_functions("/api/${add(1, 2)}?_t=${get_timestamp()}"),
|
parser.regex_findall_functions("/api/${add(1, 2)}?_t=${get_timestamp()}"),
|
||||||
["add(1, 2)", "get_timestamp()"]
|
[('add', '1, 2'), ('get_timestamp', '')]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.extract_functions("abc${func(1, 2, a=3, b=4)}def"),
|
parser.regex_findall_functions("abc${func(1, 2, a=3, b=4)}def"),
|
||||||
["func(1, 2, a=3, b=4)"]
|
[('func', '1, 2, a=3, b=4')]
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_data(self):
|
def test_parse_data(self):
|
||||||
@@ -172,7 +205,7 @@ class TestParser(unittest.TestCase):
|
|||||||
functions_mapping = {
|
functions_mapping = {
|
||||||
"add_one": lambda x: x + 1
|
"add_one": lambda x: x + 1
|
||||||
}
|
}
|
||||||
result = parser.parse_data(content, variables_mapping, functions_mapping)
|
result = parser.eval_lazy_data(content, variables_mapping, functions_mapping)
|
||||||
self.assertEqual("/api/users/1000", result["request"]["url"])
|
self.assertEqual("/api/users/1000", result["request"]["url"])
|
||||||
self.assertEqual("abc123", result["request"]["headers"]["token"])
|
self.assertEqual("abc123", result["request"]["headers"]["token"])
|
||||||
self.assertEqual("POST", result["request"]["method"])
|
self.assertEqual("POST", result["request"]["method"])
|
||||||
@@ -182,7 +215,7 @@ class TestParser(unittest.TestCase):
|
|||||||
self.assertEqual("", result["request"]["data"]["empty_str"])
|
self.assertEqual("", result["request"]["data"]["empty_str"])
|
||||||
self.assertEqual("abc4def", result["request"]["data"]["value"])
|
self.assertEqual("abc4def", result["request"]["data"]["value"])
|
||||||
|
|
||||||
def test_parse_data_variables(self):
|
def test_eval_lazy_data(self):
|
||||||
variables_mapping = {
|
variables_mapping = {
|
||||||
"var_1": "abc",
|
"var_1": "abc",
|
||||||
"var_2": "def",
|
"var_2": "def",
|
||||||
@@ -192,66 +225,150 @@ class TestParser(unittest.TestCase):
|
|||||||
"var_6": None
|
"var_6": None
|
||||||
}
|
}
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("$var_1", variables_mapping),
|
parser.eval_lazy_data("$var_1", variables_mapping=variables_mapping),
|
||||||
"abc"
|
"abc"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("var_1", variables_mapping),
|
parser.eval_lazy_data("var_1", variables_mapping=variables_mapping),
|
||||||
"var_1"
|
"var_1"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("$var_1#XYZ", variables_mapping),
|
parser.eval_lazy_data("$var_1#XYZ", variables_mapping=variables_mapping),
|
||||||
"abc#XYZ"
|
"abc#XYZ"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("/$var_1/$var_2/var3", variables_mapping),
|
parser.eval_lazy_data("/$var_1/$var_2/var3", variables_mapping=variables_mapping),
|
||||||
"/abc/def/var3"
|
"/abc/def/var3"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("/$var_1/$var_2/$var_1", variables_mapping),
|
parser.eval_lazy_data("/$var_1/$var_2/$var_1", variables_mapping=variables_mapping),
|
||||||
"/abc/def/abc"
|
"/abc/def/abc"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_string_variables("${func($var_1, $var_2, xyz)}", variables_mapping, {}),
|
parser.eval_lazy_data("$var_3", variables_mapping=variables_mapping),
|
||||||
"${func(abc, def, xyz)}"
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
parser.parse_data("$var_3", variables_mapping),
|
|
||||||
123
|
123
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("$var_4", variables_mapping),
|
parser.eval_lazy_data("$var_4", variables_mapping=variables_mapping),
|
||||||
{"a": 1}
|
{"a": 1}
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("$var_5", variables_mapping),
|
parser.eval_lazy_data("$var_5", variables_mapping=variables_mapping),
|
||||||
True
|
True
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("abc$var_5", variables_mapping),
|
parser.eval_lazy_data("abc$var_5", variables_mapping=variables_mapping),
|
||||||
"abcTrue"
|
"abcTrue"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("abc$var_4", variables_mapping),
|
parser.eval_lazy_data("abc$var_4", variables_mapping=variables_mapping),
|
||||||
"abc{'a': 1}"
|
"abc{'a': 1}"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("$var_6", variables_mapping),
|
parser.eval_lazy_data("$var_6", variables_mapping=variables_mapping),
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
||||||
with self.assertRaises(exceptions.VariableNotFound):
|
with self.assertRaises(exceptions.VariableNotFound):
|
||||||
parser.parse_data("/api/$SECRET_KEY", variables_mapping)
|
parser.eval_lazy_data("/api/$SECRET_KEY", variables_mapping=variables_mapping)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data(["$var_1", "$var_2"], variables_mapping),
|
parser.eval_lazy_data(["$var_1", "$var_2"], variables_mapping=variables_mapping),
|
||||||
["abc", "def"]
|
["abc", "def"]
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data({"$var_1": "$var_2"}, variables_mapping),
|
parser.eval_lazy_data({"$var_1": "$var_2"}, variables_mapping=variables_mapping),
|
||||||
{"abc": "def"}
|
{"abc": "def"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_lazy_string(self):
|
||||||
|
variables_mapping = {
|
||||||
|
"var_1": "abc",
|
||||||
|
"var_2": "def",
|
||||||
|
"var_3": 123,
|
||||||
|
"var_4": {"a": 1},
|
||||||
|
"var_5": True,
|
||||||
|
"var_6": None
|
||||||
|
}
|
||||||
|
check_variables_set = variables_mapping.keys()
|
||||||
|
functions_mapping = {
|
||||||
|
"func1": lambda x,y: str(x) + str(y)
|
||||||
|
}
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_1", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}")
|
||||||
|
self.assertEqual(var._args, ["var_1"])
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCabc")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_1$var_3", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}{}")
|
||||||
|
self.assertEqual(var._args, ["var_1", "var_3"])
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCabc123")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_1/$var_3", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}/{}")
|
||||||
|
self.assertEqual(var._args, ["var_1", "var_3"])
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCabc/123")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_1/", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}/")
|
||||||
|
self.assertEqual(var._args, ["var_1"])
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCabc/")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_1$", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}$")
|
||||||
|
self.assertEqual(var._args, ["var_1"])
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCabc$")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_1{", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}{")
|
||||||
|
self.assertEqual(var._args, ["var_1"])
|
||||||
|
# self.assertEqual(var.to_value(variables_mapping), "ABCabc{")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$$var_1{", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC${}{")
|
||||||
|
self.assertEqual(var._args, ["var_1"])
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_1${", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}${")
|
||||||
|
self.assertEqual(var._args, ["var_1"])
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_1${a", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}${a")
|
||||||
|
self.assertEqual(var._args, ["var_1"])
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_1/$var_2/$var_1", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}/{}/{}")
|
||||||
|
self.assertEqual(var._args, ["var_1", "var_2", "var_1"])
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCabc/def/abc")
|
||||||
|
|
||||||
|
var = parser.LazyString("func1($var_1, $var_3)", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "func1({}, {})")
|
||||||
|
self.assertEqual(var._args, ["var_1", "var_3"])
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "func1(abc, 123)")
|
||||||
|
|
||||||
|
var = parser.LazyString("${func1($var_1, $var_3)}", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "{}")
|
||||||
|
self.assertIsInstance(var._args[0], parser.LazyFunction)
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "abc123")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC${func1($var_1, $var_3)}DE", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}DE")
|
||||||
|
self.assertIsInstance(var._args[0], parser.LazyFunction)
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCabc123DE")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC${func1($var_1, $var_3)}$var_5", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}{}")
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCabc123True")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC${func1($var_1, $var_3)}DE$var_4", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}DE{}")
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCabc123DE{'a': 1}")
|
||||||
|
|
||||||
|
var = parser.LazyString("ABC$var_5${func1($var_1, $var_3)}", functions_mapping, check_variables_set)
|
||||||
|
self.assertEqual(var._string, "ABC{}{}")
|
||||||
|
self.assertEqual(var.to_value(variables_mapping), "ABCTrueabc123")
|
||||||
|
|
||||||
def test_parse_data_multiple_identical_variables(self):
|
def test_parse_data_multiple_identical_variables(self):
|
||||||
variables_mapping = {
|
variables_mapping = {
|
||||||
"userid": 100,
|
"userid": 100,
|
||||||
@@ -259,7 +376,7 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
content = "/users/$userid/training/$data?userId=$userid&data=$data"
|
content = "/users/$userid/training/$data?userId=$userid&data=$data"
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data(content, variables_mapping),
|
parser.eval_lazy_data(content, variables_mapping=variables_mapping),
|
||||||
"/users/100/training/1498?userId=100&data=1498"
|
"/users/100/training/1498?userId=100&data=1498"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -270,36 +387,35 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
content = "/users/$user/$userid/$data?userId=$userid&data=$data"
|
content = "/users/$user/$userid/$data?userId=$userid&data=$data"
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data(content, variables_mapping),
|
parser.eval_lazy_data(content, variables_mapping=variables_mapping),
|
||||||
"/users/100/1000/1498?userId=1000&data=1498"
|
"/users/100/1000/1498?userId=1000&data=1498"
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_parse_data_functions(self):
|
def test_parse_data_functions(self):
|
||||||
import random, string
|
import random, string
|
||||||
functions_mapping = {
|
functions_mapping = {
|
||||||
"gen_random_string": lambda str_len: ''.join(random.choice(string.ascii_letters + string.digits) \
|
"gen_random_string": gen_random_string
|
||||||
for _ in range(str_len))
|
|
||||||
}
|
}
|
||||||
result = parser.parse_data("${gen_random_string(5)}", functions_mapping=functions_mapping)
|
result = parser.eval_lazy_data("${gen_random_string(5)}", functions_mapping=functions_mapping)
|
||||||
self.assertEqual(len(result), 5)
|
self.assertEqual(len(result), 5)
|
||||||
|
|
||||||
add_two_nums = lambda a, b=1: a + b
|
add_two_nums = lambda a, b=1: a + b
|
||||||
functions_mapping["add_two_nums"] = add_two_nums
|
functions_mapping["add_two_nums"] = add_two_nums
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("${add_two_nums(1)}", functions_mapping=functions_mapping),
|
parser.eval_lazy_data("${add_two_nums(1)}", functions_mapping=functions_mapping),
|
||||||
2
|
2
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("${add_two_nums(1, 2)}", functions_mapping=functions_mapping),
|
parser.eval_lazy_data("${add_two_nums(1, 2)}", functions_mapping=functions_mapping),
|
||||||
3
|
3
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parser.parse_data("/api/${add_two_nums(1, 2)}", functions_mapping=functions_mapping),
|
parser.eval_lazy_data("/api/${add_two_nums(1, 2)}", functions_mapping=functions_mapping),
|
||||||
"/api/3"
|
"/api/3"
|
||||||
)
|
)
|
||||||
|
|
||||||
with self.assertRaises(exceptions.FunctionNotFound):
|
with self.assertRaises(exceptions.FunctionNotFound):
|
||||||
parser.parse_data("/api/${gen_md5(abc)}")
|
parser.eval_lazy_data("/api/${gen_md5(abc)}", functions_mapping=functions_mapping)
|
||||||
|
|
||||||
def test_parse_data_testcase(self):
|
def test_parse_data_testcase(self):
|
||||||
variables = {
|
variables = {
|
||||||
@@ -323,7 +439,11 @@ class TestParser(unittest.TestCase):
|
|||||||
},
|
},
|
||||||
"body": "$data"
|
"body": "$data"
|
||||||
}
|
}
|
||||||
parsed_testcase = parser.parse_data(testcase_template, variables, functions)
|
parsed_testcase = parser.eval_lazy_data(
|
||||||
|
testcase_template,
|
||||||
|
variables_mapping=variables,
|
||||||
|
functions_mapping=functions
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
parsed_testcase["url"],
|
parsed_testcase["url"],
|
||||||
"http://127.0.0.1:5000/api/users/1000/3"
|
"http://127.0.0.1:5000/api/users/1000/3"
|
||||||
@@ -345,25 +465,133 @@ class TestParser(unittest.TestCase):
|
|||||||
3
|
3
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_substitute_variables(self):
|
def test_parse_variables_mapping(self):
|
||||||
content = {
|
variables = {
|
||||||
'request': {
|
"varA": "123$varB",
|
||||||
'url': '/api/users/$uid?id=$id',
|
"varB": "456$varC",
|
||||||
'headers': {'token': '$token'}
|
"varC": "${sum_two($a, $b)}",
|
||||||
}
|
"a": 1,
|
||||||
|
"b": 2
|
||||||
}
|
}
|
||||||
variables_mapping = {"$uid": 1000, "$id": 2}
|
functions = {
|
||||||
substituted_data = parser.substitute_variables(content, variables_mapping)
|
"sum_two": sum_two
|
||||||
self.assertEqual(substituted_data["request"]["url"], "/api/users/1000?id=2")
|
}
|
||||||
self.assertEqual(substituted_data["request"]["headers"], {'token': '$token'})
|
prepared_variables = parser.prepare_lazy_data(variables, functions, variables.keys())
|
||||||
|
parsed_variables = parser.parse_variables_mapping(prepared_variables)
|
||||||
|
self.assertEqual(parsed_variables["varA"], "1234563")
|
||||||
|
self.assertEqual(parsed_variables["varB"], "4563")
|
||||||
|
self.assertEqual(parsed_variables["varC"], 3)
|
||||||
|
|
||||||
|
def test_parse_variables_mapping_fix_duplicate_function_call(self):
|
||||||
|
# fix duplicate function calling
|
||||||
|
variables = {
|
||||||
|
"varA": "$varB",
|
||||||
|
"varB": "${gen_random_string(5)}"
|
||||||
|
}
|
||||||
|
functions = {
|
||||||
|
"gen_random_string": gen_random_string
|
||||||
|
}
|
||||||
|
prepared_variables = parser.prepare_lazy_data(variables, functions, variables.keys())
|
||||||
|
parsed_variables = parser.parse_variables_mapping(prepared_variables)
|
||||||
|
self.assertEqual(parsed_variables["varA"], parsed_variables["varB"])
|
||||||
|
|
||||||
|
def test_parse_variables_mapping_dead_circle(self):
|
||||||
|
variables = {
|
||||||
|
"varA": "$varB",
|
||||||
|
"varB": "123$varC"
|
||||||
|
}
|
||||||
|
check_variables_set = {"varA", "varB", "varC"}
|
||||||
|
prepared_variables = parser.prepare_lazy_data(variables, {}, check_variables_set)
|
||||||
|
with self.assertRaises(exceptions.VariableNotFound):
|
||||||
|
parser.parse_variables_mapping(prepared_variables)
|
||||||
|
|
||||||
|
def test_parse_variables_mapping_not_found(self):
|
||||||
|
variables = {
|
||||||
|
"varA": "123$varB",
|
||||||
|
"varB": "456$varC",
|
||||||
|
"varC": "${sum_two($a, $b)}",
|
||||||
|
"b": 2
|
||||||
|
}
|
||||||
|
functions = {
|
||||||
|
"sum_two": sum_two
|
||||||
|
}
|
||||||
|
with self.assertRaises(exceptions.VariableNotFound):
|
||||||
|
parser.prepare_lazy_data(variables, functions, variables.keys())
|
||||||
|
|
||||||
|
def test_parse_variables_mapping_ref_self(self):
|
||||||
|
variables = {
|
||||||
|
"varC": "${sum_two($a, $b)}",
|
||||||
|
"a": 1,
|
||||||
|
"b": 2,
|
||||||
|
"token": "$token"
|
||||||
|
}
|
||||||
|
functions = {
|
||||||
|
"sum_two": sum_two
|
||||||
|
}
|
||||||
|
prepared_variables = parser.prepare_lazy_data(variables, functions, variables.keys())
|
||||||
|
with self.assertRaises(exceptions.VariableNotFound):
|
||||||
|
parser.parse_variables_mapping(prepared_variables)
|
||||||
|
|
||||||
|
def test_parse_variables_mapping_2(self):
|
||||||
|
variables = {
|
||||||
|
"host2": "https://httprunner.org",
|
||||||
|
"num3": "${sum_two($num2, 4)}",
|
||||||
|
"num2": "${sum_two($num1, 3)}",
|
||||||
|
"num1": "${sum_two(1, 2)}"
|
||||||
|
}
|
||||||
|
functions = {
|
||||||
|
"sum_two": sum_two
|
||||||
|
}
|
||||||
|
prepared_variables = parser.prepare_lazy_data(variables, functions, variables.keys())
|
||||||
|
parsed_testcase = parser.parse_variables_mapping(prepared_variables)
|
||||||
|
self.assertEqual(parsed_testcase["num3"], 10)
|
||||||
|
self.assertEqual(parsed_testcase["num2"], 6)
|
||||||
|
self.assertEqual(parsed_testcase["num1"], 3)
|
||||||
|
|
||||||
|
def test_prepare_lazy_data(self):
|
||||||
|
variables = {
|
||||||
|
"host": "https://httprunner.org",
|
||||||
|
"num4": "${sum_two($num0, 5)}",
|
||||||
|
"num3": "${sum_two($num2, 4)}",
|
||||||
|
"num2": "${sum_two($num1, 3)}",
|
||||||
|
"num1": "${sum_two(1, 2)}",
|
||||||
|
"num0": 0
|
||||||
|
}
|
||||||
|
functions = {
|
||||||
|
"sum_two": sum_two
|
||||||
|
}
|
||||||
|
parser.prepare_lazy_data(
|
||||||
|
variables,
|
||||||
|
functions,
|
||||||
|
variables.keys()
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_prepare_lazy_data_not_found(self):
|
||||||
|
variables = {
|
||||||
|
"host": "https://httprunner.org",
|
||||||
|
"num4": "${sum_two($num0, 5)}",
|
||||||
|
"num3": "${sum_two($num2, 4)}",
|
||||||
|
"num2": "${sum_two($num1, 3)}",
|
||||||
|
"num1": "${sum_two(1, 2)}"
|
||||||
|
}
|
||||||
|
functions = {
|
||||||
|
"sum_two": sum_two
|
||||||
|
}
|
||||||
|
with self.assertRaises(exceptions.VariableNotFound):
|
||||||
|
parser.prepare_lazy_data(
|
||||||
|
variables,
|
||||||
|
functions,
|
||||||
|
variables.keys()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestParser(unittest.TestCase):
|
||||||
|
|
||||||
def test_parse_parameters_raw_list(self):
|
def test_parse_parameters_raw_list(self):
|
||||||
parameters = [
|
parameters = [
|
||||||
{"user_agent": ["iOS/10.1", "iOS/10.2", "iOS/10.3"]},
|
{"user_agent": ["iOS/10.1", "iOS/10.2", "iOS/10.3"]},
|
||||||
{"username-password": [("user1", "111111"), ["test2", "222222"]]}
|
{"username-password": [("user1", "111111"), ["test2", "222222"]]}
|
||||||
]
|
]
|
||||||
variables_mapping = {}
|
|
||||||
functions_mapping = {}
|
|
||||||
cartesian_product_parameters = parser.parse_parameters(parameters)
|
cartesian_product_parameters = parser.parse_parameters(parameters)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
len(cartesian_product_parameters),
|
len(cartesian_product_parameters),
|
||||||
@@ -441,20 +669,18 @@ class TestParser(unittest.TestCase):
|
|||||||
testcases = tests_mapping["testcases"]
|
testcases = tests_mapping["testcases"]
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
testcases[0]["config"]["variables"]["var_c"],
|
testcases[0]["config"]["variables"]["var_c"],
|
||||||
"${sum_two(1, 2)}"
|
"${sum_two($var_a, $var_b)}"
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
testcases[0]["config"]["variables"]["PROJECT_KEY"],
|
testcases[0]["config"]["variables"]["PROJECT_KEY"],
|
||||||
"${ENV(PROJECT_KEY)}"
|
"${ENV(PROJECT_KEY)}"
|
||||||
)
|
)
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
parsed_testcases = parsed_tests_mapping["testcases"]
|
|
||||||
self.assertIsInstance(parsed_testcases, list)
|
self.assertIsInstance(parsed_testcases, list)
|
||||||
test_dict1 = parsed_testcases[0]["teststeps"][0]
|
test_dict1 = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict1["variables"]["var_c"], 3)
|
self.assertEqual(test_dict1["variables"]["var_c"].raw_string, "${sum_two($var_a, $var_b)}")
|
||||||
self.assertEqual(test_dict1["variables"]["PROJECT_KEY"], "ABCDEFGH")
|
self.assertEqual(test_dict1["variables"]["PROJECT_KEY"].raw_string, "${ENV(PROJECT_KEY)}")
|
||||||
self.assertEqual(test_dict1["variables"]["var_d"], test_dict1["variables"]["var_e"])
|
self.assertIsInstance(parsed_testcases[0]["config"]["name"], parser.LazyString)
|
||||||
self.assertEqual(parsed_testcases[0]["config"]["name"], '1230')
|
|
||||||
|
|
||||||
def test_parse_tests_override_variables(self):
|
def test_parse_tests_override_variables(self):
|
||||||
tests_mapping = {
|
tests_mapping = {
|
||||||
@@ -480,10 +706,10 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict1_variables = parsed_tests_mapping["testcases"][0]["teststeps"][0]["variables"]
|
test_dict1_variables = parsed_testcases[0]["teststeps"][0]["variables"]
|
||||||
self.assertEqual(test_dict1_variables["creator"], "user_test_001")
|
self.assertEqual(test_dict1_variables["creator"], "user_test_001")
|
||||||
self.assertEqual(test_dict1_variables["username"], "user_test_001")
|
self.assertEqual(test_dict1_variables["username"].raw_string, "$creator")
|
||||||
|
|
||||||
def test_parse_tests_base_url_priority(self):
|
def test_parse_tests_base_url_priority(self):
|
||||||
""" base_url & verify: priority test_dict > config
|
""" base_url & verify: priority test_dict > config
|
||||||
@@ -509,9 +735,9 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
test_dict = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict["request"]["url"], "https://httprunner.org/api1")
|
self.assertEqual(test_dict["request"]["url"], "/api1")
|
||||||
self.assertEqual(test_dict["request"]["verify"], True)
|
self.assertEqual(test_dict["request"]["verify"], True)
|
||||||
|
|
||||||
def test_parse_tests_base_url_path_with_variable(self):
|
def test_parse_tests_base_url_path_with_variable(self):
|
||||||
@@ -537,9 +763,11 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
test_dict = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict["request"]["url"], "https://httprunner.org/api1")
|
self.assertEqual(test_dict["variables"]["host2"], "https://httprunner.org")
|
||||||
|
parsed_test_dict = parser.parse_lazy_data(test_dict, test_dict["variables"])
|
||||||
|
self.assertEqual(parsed_test_dict["request"]["url"], "https://httprunner.org/api1")
|
||||||
|
|
||||||
def test_parse_tests_base_url_test_dict(self):
|
def test_parse_tests_base_url_test_dict(self):
|
||||||
tests_mapping = {
|
tests_mapping = {
|
||||||
@@ -565,54 +793,12 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
test_dict = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict["request"]["url"], "https://httprunner.org/api1")
|
parsed_test_dict = parser.parse_lazy_data(test_dict, test_dict["variables"])
|
||||||
|
self.assertEqual(parsed_test_dict["base_url"], "https://httprunner.org")
|
||||||
def test_parse_data_with_variables(self):
|
|
||||||
variables = {
|
|
||||||
"host2": "https://httprunner.org",
|
|
||||||
"num3": "${sum_two($num2, 4)}",
|
|
||||||
"num2": "${sum_two($num1, 3)}",
|
|
||||||
"num1": "${sum_two(1, 2)}"
|
|
||||||
}
|
|
||||||
from tests.debugtalk import sum_two
|
|
||||||
functions = {
|
|
||||||
"sum_two": sum_two
|
|
||||||
}
|
|
||||||
parsed_testcase = parser.parse_data(variables, variables, functions)
|
|
||||||
self.assertEqual(parsed_testcase["num3"], 10)
|
|
||||||
self.assertEqual(parsed_testcase["num2"], 6)
|
|
||||||
self.assertEqual(parsed_testcase["num1"], 3)
|
|
||||||
|
|
||||||
def test_parse_data_with_variables_not_found(self):
|
|
||||||
variables = {
|
|
||||||
"host": "https://httprunner.org",
|
|
||||||
"num4": "${sum_two($num0, 5)}",
|
|
||||||
"num3": "${sum_two($num2, 4)}",
|
|
||||||
"num2": "${sum_two($num1, 3)}",
|
|
||||||
"num1": "${sum_two(1, 2)}"
|
|
||||||
}
|
|
||||||
from tests.debugtalk import sum_two
|
|
||||||
functions = {
|
|
||||||
"sum_two": sum_two
|
|
||||||
}
|
|
||||||
with self.assertRaises(exceptions.VariableNotFound):
|
|
||||||
parser.parse_data(variables, variables, functions)
|
|
||||||
|
|
||||||
parsed_testcase = parser.parse_data(
|
|
||||||
variables,
|
|
||||||
variables,
|
|
||||||
functions,
|
|
||||||
raise_if_variable_not_found=False
|
|
||||||
)
|
|
||||||
self.assertEqual(parsed_testcase["num3"], 10)
|
|
||||||
self.assertEqual(parsed_testcase["num2"], 6)
|
|
||||||
self.assertEqual(parsed_testcase["num1"], 3)
|
|
||||||
self.assertEqual(parsed_testcase["num4"], "${sum_two($num0, 5)}")
|
|
||||||
|
|
||||||
def test_parse_tests_variable_with_function(self):
|
def test_parse_tests_variable_with_function(self):
|
||||||
from tests.debugtalk import sum_two, gen_random_string
|
|
||||||
tests_mapping = {
|
tests_mapping = {
|
||||||
"project_mapping": {
|
"project_mapping": {
|
||||||
"functions": {
|
"functions": {
|
||||||
@@ -652,18 +838,20 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
test_dict = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict["variables"]["num3"], 10)
|
variables = parser.parse_variables_mapping(test_dict["variables"])
|
||||||
self.assertEqual(test_dict["variables"]["num2"], 6)
|
self.assertEqual(variables["num3"], 10)
|
||||||
self.assertEqual(test_dict["variables"]["str1"], test_dict["variables"]["str2"])
|
self.assertEqual(variables["num2"], 6)
|
||||||
|
parsed_test_dict = parser.parse_lazy_data(test_dict, variables)
|
||||||
|
self.assertEqual(parsed_test_dict["base_url"], "https://httprunner.org")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
test_dict["request"]["url"],
|
parsed_test_dict["request"]["url"],
|
||||||
"https://httprunner.org/api1/?num1=3&num2=6&num3=10"
|
"/api1/?num1=3&num2=6&num3=10"
|
||||||
)
|
)
|
||||||
|
self.assertEqual(variables["str1"], variables["str2"])
|
||||||
|
|
||||||
def test_parse_tests_variable_not_found(self):
|
def test_parse_tests_variable_not_found(self):
|
||||||
from tests.debugtalk import sum_two
|
|
||||||
tests_mapping = {
|
tests_mapping = {
|
||||||
"project_mapping": {
|
"project_mapping": {
|
||||||
"functions": {
|
"functions": {
|
||||||
@@ -699,15 +887,8 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
with self.assertRaises(exceptions.VariableNotFound):
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
parser.parse_tests(tests_mapping)
|
||||||
self.assertEqual(test_dict["variables"]["num3"], 10)
|
|
||||||
self.assertEqual(test_dict["variables"]["num2"], 6)
|
|
||||||
self.assertEqual(test_dict["variables"]["num4"], "${sum_two($num0, 5)}")
|
|
||||||
self.assertEqual(
|
|
||||||
test_dict["request"]["url"],
|
|
||||||
"https://httprunner.org/api1/?num1=3&num2=6&num3=10&num4=${sum_two($num0, 5)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_parse_tests_base_url_teststep_empty(self):
|
def test_parse_tests_base_url_teststep_empty(self):
|
||||||
""" base_url & verify: priority test_dict > config
|
""" base_url & verify: priority test_dict > config
|
||||||
@@ -733,9 +914,9 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
test_dict = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict["request"]["url"], "https://debugtalk.com/api1")
|
self.assertEqual(str(test_dict["base_url"]), 'LazyString($host)')
|
||||||
self.assertEqual(test_dict["request"]["verify"], True)
|
self.assertEqual(test_dict["request"]["verify"], True)
|
||||||
|
|
||||||
def test_parse_tests_verify_config_set(self):
|
def test_parse_tests_verify_config_set(self):
|
||||||
@@ -758,8 +939,8 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
test_dict = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict["request"]["verify"], False)
|
self.assertEqual(test_dict["request"]["verify"], False)
|
||||||
|
|
||||||
def test_parse_tests_verify_config_unset(self):
|
def test_parse_tests_verify_config_unset(self):
|
||||||
@@ -781,8 +962,8 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
test_dict = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict["request"]["verify"], True)
|
self.assertEqual(test_dict["request"]["verify"], True)
|
||||||
|
|
||||||
def test_parse_tests_verify_step_set_false(self):
|
def test_parse_tests_verify_step_set_false(self):
|
||||||
@@ -805,8 +986,8 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
test_dict = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict["request"]["verify"], False)
|
self.assertEqual(test_dict["request"]["verify"], False)
|
||||||
|
|
||||||
def test_parse_tests_verify_nested_testcase_unset(self):
|
def test_parse_tests_verify_nested_testcase_unset(self):
|
||||||
@@ -840,8 +1021,8 @@ class TestParser(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
parsed_tests_mapping = parser.parse_tests(tests_mapping)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_dict = parsed_tests_mapping["testcases"][0]["teststeps"][0]
|
test_dict = parsed_testcases[0]["teststeps"][0]
|
||||||
self.assertEqual(test_dict["teststeps"][0]["request"]["verify"], False)
|
self.assertEqual(test_dict["teststeps"][0]["request"]["verify"], False)
|
||||||
|
|
||||||
def test_parse_environ(self):
|
def test_parse_environ(self):
|
||||||
@@ -851,7 +1032,7 @@ class TestParser(unittest.TestCase):
|
|||||||
{"PROJECT_KEY": "${ENV(PROJECT_KEY)}"}
|
{"PROJECT_KEY": "${ENV(PROJECT_KEY)}"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
result = parser.parse_data(content)
|
result = parser.eval_lazy_data(content)
|
||||||
|
|
||||||
content = {
|
content = {
|
||||||
"variables": [
|
"variables": [
|
||||||
@@ -859,7 +1040,7 @@ class TestParser(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
with self.assertRaises(exceptions.ParamsError):
|
with self.assertRaises(exceptions.ParamsError):
|
||||||
parser.parse_data(content)
|
parser.eval_lazy_data(content)
|
||||||
|
|
||||||
content = {
|
content = {
|
||||||
"variables": [
|
"variables": [
|
||||||
@@ -867,7 +1048,7 @@ class TestParser(unittest.TestCase):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
with self.assertRaises(exceptions.ParamsError):
|
with self.assertRaises(exceptions.ParamsError):
|
||||||
parser.parse_data(content)
|
parser.eval_lazy_data(content)
|
||||||
|
|
||||||
def test_extend_with_api(self):
|
def test_extend_with_api(self):
|
||||||
loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
|
loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
|
||||||
@@ -888,18 +1069,18 @@ class TestParser(unittest.TestCase):
|
|||||||
'url': '/api/get-token',
|
'url': '/api/get-token',
|
||||||
'method': 'POST',
|
'method': 'POST',
|
||||||
'headers': {'user_agent': '$user_agent', 'device_sn': '$device_sn', 'os_platform': '$os_platform', 'app_version': '$app_version'},
|
'headers': {'user_agent': '$user_agent', 'device_sn': '$device_sn', 'os_platform': '$os_platform', 'app_version': '$app_version'},
|
||||||
'json': {'sign': '${get_sign($user_agent, $device_sn, $os_platform, $app_version)}'}
|
'json': {'sign': '${get_sign($device_sn, $os_platform, $app_version)}'}
|
||||||
},
|
},
|
||||||
'validate': [
|
'validate': [
|
||||||
{'eq': ['status_code', 201]},
|
{"check": "status_code", "comparator": "equals", "expect": 201},
|
||||||
{'len_eq': ['content.token', 32]}
|
{"check": "content.token", "comparator": "length_equals", "expect": 32}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
extended_block = parser._extend_with_api(test_block, api_def_dict)
|
parser._extend_with_api(test_block, api_def_dict)
|
||||||
self.assertEqual(extended_block["base_url"], "https://debugtalk.com")
|
self.assertEqual(test_block["base_url"], "https://debugtalk.com")
|
||||||
self.assertEqual(extended_block["name"], "override block")
|
self.assertEqual(test_block["name"], "override block")
|
||||||
self.assertEqual({'var': 123}, extended_block["variables"])
|
self.assertEqual({'var': 123}, test_block["variables"])
|
||||||
self.assertIn({'check': 'status_code', 'expect': 201, 'comparator': 'eq'}, extended_block["validate"])
|
self.assertIn({'check': 'status_code', 'expect': 201, 'comparator': 'equals'}, test_block["validate"])
|
||||||
self.assertIn({'check': 'content.token', 'comparator': 'len_eq', 'expect': 32}, extended_block["validate"])
|
self.assertIn({'check': 'content.token', 'comparator': 'length_equals', 'expect': 32}, test_block["validate"])
|
||||||
self.assertEqual(extended_block["times"], 3)
|
self.assertEqual(test_block["times"], 3)
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from httprunner import exceptions, loader, runner
|
from httprunner import loader, parser, runner
|
||||||
from httprunner.utils import deep_update_dict
|
|
||||||
from tests.api_server import HTTPBIN_SERVER
|
from tests.api_server import HTTPBIN_SERVER
|
||||||
from tests.base import ApiServerUnittest
|
from tests.base import ApiServerUnittest
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@ class TestRunner(ApiServerUnittest):
|
|||||||
"base_url": "http://127.0.0.1",
|
"base_url": "http://127.0.0.1",
|
||||||
"verify": False
|
"verify": False
|
||||||
}
|
}
|
||||||
self.test_runner = runner.Runner(config, self.debugtalk_functions)
|
self.test_runner = runner.Runner(config)
|
||||||
self.reset_all()
|
self.reset_all()
|
||||||
|
|
||||||
def reset_all(self):
|
def reset_all(self):
|
||||||
@@ -36,204 +35,253 @@ class TestRunner(ApiServerUnittest):
|
|||||||
]
|
]
|
||||||
|
|
||||||
for testcase_file_path in testcase_file_path_list:
|
for testcase_file_path in testcase_file_path_list:
|
||||||
testcases = loader.load_file(testcase_file_path)
|
tests_mapping = loader.load_tests(testcase_file_path)
|
||||||
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
config_dict = {}
|
parsed_testcase = parsed_testcases[0]
|
||||||
test_runner = runner.Runner(config_dict, self.debugtalk_functions)
|
test_runner = runner.Runner(parsed_testcase["config"])
|
||||||
|
test_runner.run_test(parsed_testcase["teststeps"][0])
|
||||||
test = testcases[0]["test"]
|
test_runner.run_test(parsed_testcase["teststeps"][1])
|
||||||
test_runner.run_test(test)
|
test_runner.run_test(parsed_testcase["teststeps"][2])
|
||||||
|
|
||||||
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": "f1219719911caae89ccc301679857ebfda115ca2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"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)
|
|
||||||
|
|
||||||
def test_run_testcase_with_hooks(self):
|
def test_run_testcase_with_hooks(self):
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
config_dict = {
|
testcases = [
|
||||||
"name": "basic test with httpbin",
|
{
|
||||||
"base_url": HTTPBIN_SERVER,
|
"config": {
|
||||||
"setup_hooks": [
|
"name": "basic test with httpbin",
|
||||||
"${sleep_N_secs(0.5)}"
|
"base_url": HTTPBIN_SERVER,
|
||||||
"${hook_print(setup)}"
|
"setup_hooks": [
|
||||||
],
|
"${sleep_N_secs(0.5)}",
|
||||||
"teardown_hooks": [
|
"${hook_print(setup)}"
|
||||||
"${sleep_N_secs(1)}",
|
],
|
||||||
"${hook_print(teardown)}"
|
"teardown_hooks": [
|
||||||
]
|
"${sleep_N_secs(1)}",
|
||||||
}
|
"${hook_print(teardown)}"
|
||||||
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": {
|
"teststeps": [
|
||||||
"sign": "f1219719911caae89ccc301679857ebfda115ca2"
|
{
|
||||||
}
|
"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
|
||||||
},
|
},
|
||||||
"validate": [
|
"testcases": testcases
|
||||||
{"check": "status_code", "expect": 200}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
test_runner = runner.Runner(config_dict, self.debugtalk_functions)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
|
parsed_testcase = parsed_testcases[0]
|
||||||
|
test_runner = runner.Runner(parsed_testcase["config"])
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
# check if testcase setup hook executed
|
# check if testcase setup hook executed
|
||||||
self.assertGreater(end_time - start_time, 0.5)
|
self.assertGreater(end_time - start_time, 0.5)
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
test_runner.run_test(test)
|
test_runner.run_test(parsed_testcase["teststeps"][0])
|
||||||
test_runner.run_test(test)
|
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
# testcase teardown hook has not been executed now
|
# testcase teardown hook has not been executed now
|
||||||
self.assertLess(end_time - start_time, 1)
|
self.assertLess(end_time - start_time, 1)
|
||||||
|
|
||||||
def test_run_testcase_with_hooks_assignment(self):
|
def test_run_testcase_with_hooks_assignment(self):
|
||||||
config_dict = {
|
testcases = [
|
||||||
"name": "basic test with httpbin",
|
{
|
||||||
"base_url": HTTPBIN_SERVER
|
"config": {
|
||||||
}
|
"name": "basic test with httpbin",
|
||||||
test = {
|
"base_url": HTTPBIN_SERVER
|
||||||
"name": "modify request headers",
|
|
||||||
"request": {
|
|
||||||
"url": "/anything",
|
|
||||||
"method": "POST",
|
|
||||||
"headers": {
|
|
||||||
"user_agent": "iOS/10.3",
|
|
||||||
"os_platform": "ios"
|
|
||||||
},
|
},
|
||||||
"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": [
|
"testcases": testcases
|
||||||
{"total": "${sum_two(1, 5)}"}
|
|
||||||
],
|
|
||||||
"validate": [
|
|
||||||
{"check": "status_code", "expect": 200}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
test_runner = runner.Runner(config_dict, self.debugtalk_functions)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_runner.run_test(test)
|
parsed_testcase = parsed_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
|
test_variables_mapping = test_runner.session_context.test_variables_mapping
|
||||||
self.assertEqual(test_variables_mapping["total"], 6)
|
self.assertEqual(test_variables_mapping["total"], 6)
|
||||||
self.assertEqual(test_variables_mapping["request"]["data"], "a=1&b=2")
|
self.assertEqual(test_variables_mapping["request"]["data"], "a=1&b=2")
|
||||||
|
|
||||||
def test_run_testcase_with_hooks_modify_request(self):
|
def test_run_testcase_with_hooks_modify_request(self):
|
||||||
config_dict = {
|
testcases = [
|
||||||
"name": "basic test with httpbin",
|
{
|
||||||
"base_url": HTTPBIN_SERVER
|
"config": {
|
||||||
}
|
"name": "basic test with httpbin",
|
||||||
test = {
|
"base_url": HTTPBIN_SERVER
|
||||||
"name": "modify request headers",
|
|
||||||
"request": {
|
|
||||||
"url": "/anything",
|
|
||||||
"method": "POST",
|
|
||||||
"headers": {
|
|
||||||
"content-type": "application/json",
|
|
||||||
"user_agent": "iOS/10.3"
|
|
||||||
},
|
},
|
||||||
"json": {
|
"teststeps": [
|
||||||
"os_platform": "ios",
|
{
|
||||||
"sign": "f1219719911caae89ccc301679857ebfda115ca2"
|
"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": [
|
"testcases": testcases
|
||||||
"${modify_request_json($request, android)}"
|
|
||||||
],
|
|
||||||
"validate": [
|
|
||||||
{"check": "status_code", "expect": 200},
|
|
||||||
{"check": "content.json.os_platform", "expect": "android"}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
test_runner = runner.Runner(config_dict, self.debugtalk_functions)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test_runner.run_test(test)
|
parsed_testcase = parsed_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):
|
def test_run_testcase_with_teardown_hooks_success(self):
|
||||||
test = {
|
testcases = [
|
||||||
"name": "get token",
|
{
|
||||||
"request": {
|
"config": {
|
||||||
"url": "http://127.0.0.1:5000/api/get-token",
|
"name": "basic test with httpbin"
|
||||||
"method": "POST",
|
|
||||||
"headers": {
|
|
||||||
"content-type": "application/json",
|
|
||||||
"user_agent": "iOS/10.3",
|
|
||||||
"device_sn": "HZfFBh6tU59EdXJ",
|
|
||||||
"os_platform": "ios",
|
|
||||||
"app_version": "2.8.6"
|
|
||||||
},
|
},
|
||||||
"json": {
|
"teststeps": [
|
||||||
"sign": "f1219719911caae89ccc301679857ebfda115ca2"
|
{
|
||||||
}
|
"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": [
|
"testcases": testcases
|
||||||
{"check": "status_code", "expect": 200}
|
|
||||||
],
|
|
||||||
"teardown_hooks": ["${teardown_hook_sleep_N_secs($response, 2)}"]
|
|
||||||
}
|
}
|
||||||
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
|
parsed_testcase = parsed_testcases[0]
|
||||||
|
test_runner = runner.Runner(parsed_testcase["config"])
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
self.test_runner.run_test(test)
|
test_runner.run_test(parsed_testcase["teststeps"][0])
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
# check if teardown function executed
|
# check if teardown function executed
|
||||||
self.assertLess(end_time - start_time, 0.5)
|
self.assertLess(end_time - start_time, 0.5)
|
||||||
|
|
||||||
def test_run_testcase_with_teardown_hooks_fail(self):
|
def test_run_testcase_with_teardown_hooks_fail(self):
|
||||||
test = {
|
testcases = [
|
||||||
"name": "get token",
|
{
|
||||||
"request": {
|
"config": {
|
||||||
"url": "http://127.0.0.1:5000/api/get-token2",
|
"name": "basic test with httpbin"
|
||||||
"method": "POST",
|
|
||||||
"headers": {
|
|
||||||
"content-type": "application/json",
|
|
||||||
"user_agent": "iOS/10.3",
|
|
||||||
"device_sn": "HZfFBh6tU59EdXJ",
|
|
||||||
"os_platform": "ios",
|
|
||||||
"app_version": "2.8.6"
|
|
||||||
},
|
},
|
||||||
"json": {
|
"teststeps": [
|
||||||
"sign": "f1219719911caae89ccc301679857ebfda115ca2"
|
{
|
||||||
}
|
"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": [
|
"testcases": testcases
|
||||||
{"check": "status_code", "expect": 404}
|
|
||||||
],
|
|
||||||
"teardown_hooks": ["${teardown_hook_sleep_N_secs($response, 2)}"]
|
|
||||||
}
|
}
|
||||||
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
|
parsed_testcase = parsed_testcases[0]
|
||||||
|
test_runner = runner.Runner(parsed_testcase["config"])
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
self.test_runner.run_test(test)
|
test_runner.run_test(parsed_testcase["teststeps"][0])
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
# check if teardown function executed
|
# check if teardown function executed
|
||||||
self.assertGreater(end_time - start_time, 2)
|
self.assertGreater(end_time - start_time, 2)
|
||||||
@@ -241,34 +289,51 @@ class TestRunner(ApiServerUnittest):
|
|||||||
def test_bugfix_type_match(self):
|
def test_bugfix_type_match(self):
|
||||||
testcase_file_path = os.path.join(
|
testcase_file_path = os.path.join(
|
||||||
os.getcwd(), 'tests/data/bugfix_type_match.yml')
|
os.getcwd(), 'tests/data/bugfix_type_match.yml')
|
||||||
testcases = loader.load_file(testcase_file_path)
|
tests_mapping = loader.load_tests(testcase_file_path)
|
||||||
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
test = testcases[1]["test"]
|
parsed_testcase = parsed_testcases[0]
|
||||||
self.test_runner.run_test(test)
|
test_runner = runner.Runner(parsed_testcase["config"])
|
||||||
|
test_runner.run_test(parsed_testcase["teststeps"][0])
|
||||||
|
|
||||||
def test_run_validate_elapsed(self):
|
def test_run_validate_elapsed(self):
|
||||||
test = {
|
testcases = [
|
||||||
"name": "get token",
|
{
|
||||||
"request": {
|
"config": {},
|
||||||
"url": "http://127.0.0.1:5000/api/get-token",
|
"teststeps": [
|
||||||
"method": "POST",
|
{
|
||||||
"headers": {
|
"name": "get token",
|
||||||
"content-type": "application/json",
|
"request": {
|
||||||
"user_agent": "iOS/10.3",
|
"url": "http://127.0.0.1:5000/api/get-token",
|
||||||
"device_sn": "HZfFBh6tU59EdXJ",
|
"method": "POST",
|
||||||
"os_platform": "ios",
|
"headers": {
|
||||||
"app_version": "2.8.6"
|
"content-type": "application/json",
|
||||||
},
|
"user_agent": "iOS/10.3",
|
||||||
"json": {
|
"device_sn": "HZfFBh6tU59EdXJ",
|
||||||
"sign": "f1219719911caae89ccc301679857ebfda115ca2"
|
"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": [
|
"testcases": testcases
|
||||||
{"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}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
self.test_runner.run_test(test)
|
parsed_testcases = parser.parse_tests(tests_mapping)
|
||||||
|
parsed_testcase = parsed_testcases[0]
|
||||||
|
test_runner = runner.Runner(parsed_testcase["config"])
|
||||||
|
test_runner.run_test(parsed_testcase["teststeps"][0])
|
||||||
@@ -61,35 +61,6 @@ class TestUtils(ApiServerUnittest):
|
|||||||
result = utils.query_json(json_content, query)
|
result = utils.query_json(json_content, query)
|
||||||
self.assertEqual(result, "L")
|
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):
|
def current_validators(self):
|
||||||
from httprunner import built_in
|
from httprunner import built_in
|
||||||
functions_mapping = loader.load_module_functions(built_in)
|
functions_mapping = loader.load_module_functions(built_in)
|
||||||
@@ -205,61 +176,6 @@ class TestUtils(ApiServerUnittest):
|
|||||||
self.assertIsInstance(ordered_dict, dict)
|
self.assertIsInstance(ordered_dict, dict)
|
||||||
self.assertIn("a", ordered_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):
|
def test_extend_variables(self):
|
||||||
raw_variables = [{"var1": "val1"}, {"var2": "val2"}]
|
raw_variables = [{"var1": "val1"}, {"var2": "val2"}]
|
||||||
override_variables = [{"var1": "val111"}, {"var3": "val3"}]
|
override_variables = [{"var1": "val111"}, {"var3": "val3"}]
|
||||||
|
|||||||
@@ -74,3 +74,101 @@ class TestValidator(unittest.TestCase):
|
|||||||
func = lambda x: x + 1
|
func = lambda x: x + 1
|
||||||
self.assertTrue(validator.is_function(func))
|
self.assertTrue(validator.is_function(func))
|
||||||
self.assertTrue(validator.is_function(validator.is_testcase))
|
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)
|
||||||
|
|||||||
22
tests/testcases/create_user.yml
Normal file
22
tests/testcases/create_user.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
- config:
|
||||||
|
name: "create user and check result."
|
||||||
|
id: create_user
|
||||||
|
base_url: "http://127.0.0.1:5000"
|
||||||
|
variables:
|
||||||
|
uid: 9001
|
||||||
|
device_sn: "TESTCASE_CREATE_XXX"
|
||||||
|
output:
|
||||||
|
- session_token
|
||||||
|
|
||||||
|
- test:
|
||||||
|
name: setup and reset all (override) for $device_sn.
|
||||||
|
testcase: testcases/setup.yml
|
||||||
|
output:
|
||||||
|
- session_token
|
||||||
|
|
||||||
|
- test:
|
||||||
|
name: create user and check result.
|
||||||
|
variables:
|
||||||
|
token: $session_token
|
||||||
|
testcase: testcases/deps/check_and_create.yml
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
- config:
|
- config:
|
||||||
name: "create user and check result."
|
name: "create user and check result."
|
||||||
id: create_and_check
|
id: create_and_check
|
||||||
@@ -6,14 +5,6 @@
|
|||||||
variables:
|
variables:
|
||||||
uid: 9001
|
uid: 9001
|
||||||
device_sn: "TESTCASE_CREATE_XXX"
|
device_sn: "TESTCASE_CREATE_XXX"
|
||||||
output:
|
|
||||||
- token
|
|
||||||
|
|
||||||
- test:
|
|
||||||
name: setup and reset all (override) for $device_sn.
|
|
||||||
testcase: testcases/setup.yml
|
|
||||||
output:
|
|
||||||
- token
|
|
||||||
|
|
||||||
- test:
|
- test:
|
||||||
name: make sure user $uid does not exist
|
name: make sure user $uid does not exist
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
base_url: "http://127.0.0.1:5000"
|
base_url: "http://127.0.0.1:5000"
|
||||||
verify: False
|
verify: False
|
||||||
output:
|
output:
|
||||||
- token
|
- session_token
|
||||||
|
|
||||||
- test:
|
- test:
|
||||||
name: get token (setup)
|
name: get token (setup)
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
os_platform: 'ios'
|
os_platform: 'ios'
|
||||||
app_version: '2.8.6'
|
app_version: '2.8.6'
|
||||||
extract:
|
extract:
|
||||||
- token: content.token
|
- session_token: content.token
|
||||||
validate:
|
validate:
|
||||||
- eq: ["status_code", 200]
|
- eq: ["status_code", 200]
|
||||||
- len_eq: ["content.token", 16]
|
- len_eq: ["content.token", 16]
|
||||||
@@ -29,4 +29,4 @@
|
|||||||
name: reset all users
|
name: reset all users
|
||||||
api: api/reset_all.yml
|
api: api/reset_all.yml
|
||||||
variables:
|
variables:
|
||||||
token: $token
|
token: $session_token
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ config:
|
|||||||
|
|
||||||
testcases:
|
testcases:
|
||||||
create user 1000 and check result.:
|
create user 1000 and check result.:
|
||||||
testcase: testcases/create_and_check.yml
|
testcase: testcases/create_user.yml
|
||||||
variables:
|
variables:
|
||||||
uid: 1000
|
uid: 1000
|
||||||
var_c: ${gen_random_string(5)}
|
var_c: ${gen_random_string(5)}
|
||||||
var_d: $var_c
|
var_d: $var_c
|
||||||
|
|
||||||
create user 1001 and check result.:
|
create user 1001 and check result.:
|
||||||
testcase: testcases/create_and_check.yml
|
testcase: testcases/create_user.yml
|
||||||
variables:
|
variables:
|
||||||
uid: 1001
|
uid: 1001
|
||||||
var_c: ${gen_random_string(5)}
|
var_c: ${gen_random_string(5)}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ config:
|
|||||||
|
|
||||||
testcases:
|
testcases:
|
||||||
create user $uid and check result for $device_sn.:
|
create user $uid and check result for $device_sn.:
|
||||||
testcase: testcases/create_and_check.yml
|
testcase: testcases/create_user.yml
|
||||||
variables:
|
variables:
|
||||||
uid: 1000
|
uid: 1000
|
||||||
device_sn: TESTSUITE_XXX
|
device_sn: TESTSUITE_XXX
|
||||||
|
|||||||
Reference in New Issue
Block a user